1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
18547: sys: PSA Crypto API implementation r=MrKevinWeiss a=Einhornhool

### Contribution description
This adds an implementation of the ARM [PSA Crypto API](https://armmbed.github.io/mbed-crypto/html/index.html) specification to RIOT. 

It is a cryptographic API that supports software and hardware backends as well as the use of multiple secure elements, which can be configured with Kconfig.
It integrates indirect, identifier based key management to support persistent storage of key material in local memory and devices with protected key storage.

A description of the implementation design and an evaluation of the processing time and memory overhead in RIOT has been published here: [Usable Security for an IoT OS: Integrating the Zoo of Embedded Crypto Components Below a Common API](https://arxiv.org/abs/2208.09281)

#### Implementation status
So far this implementation supports the following operations:
- Volatile key storage
- AES in CBC mode
- Hashes (MD5, SHA1, SHA224, SHA256)
- HMAC SHA256
- ECDSA with NIST P192 and P256 curves

The following backends are supported so far:
- RIOT Cipher Module
- RIOT Hash Module
- Micro ECC library package
- Cryptocell 310 hardware accelerator on the Nordic NRF52840dk
- Microchip ATECC608A secure element

Other operations and backends as well as persistent key storage can and will be implemented by me and anyone who wants to contribute in the future.

### Testing procedure
So far there is a show case application in `examples/psa_crypto` to demonstrate the usage and configuration of different backends of the API (refer to the application README for more information). 


Co-authored-by: Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
This commit is contained in:
bors[bot] 2023-09-04 08:15:08 +00:00 committed by GitHub
commit 9be022afd8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
139 changed files with 23954 additions and 68 deletions

View File

@ -36,7 +36,15 @@ static const i2c_conf_t i2c_config[] = {
.scl = 27,
.sda = 26,
.speed = I2C_SPEED_NORMAL
},
#ifdef BOARD_NRF52840DK
{
.dev = NRF_TWIM0,
.scl = 28,
.sda = 29,
.speed = I2C_SPEED_NORMAL
}
#endif
};
#define I2C_NUMOF ARRAY_SIZE(i2c_config)
/** @} */

View File

@ -69,6 +69,15 @@ config CPU_MODEL_NRF52840XXAA
select HAS_BLE_PHY_CODED
select HAS_RADIO_NRF802154
select HAS_PERIPH_UART_NONBLOCKING
select HAS_PERIPH_HASH_SHA_1
select HAS_PERIPH_HASH_SHA_224
select HAS_PERIPH_HASH_SHA_256
select HAS_PERIPH_HASH_SHA_512
select HAS_PERIPH_HMAC_SHA_256
select HAS_PERIPH_CIPHER_AES_128_CBC
select HAS_PERIPH_ECC_P192R1
select HAS_PERIPH_ECC_P256R1
select HAS_PERIPH_CRYPTOCELL_310
## CPU common symbols
config CPU_FAM

View File

@ -36,5 +36,6 @@ ifneq (,$(filter periph_spi,$(USEMODULE)))
USEMODULE += periph_spi_gpio_mode
endif
include $(RIOTCPU)/nrf52/periph/Makefile.dep
include $(RIOTCPU)/nrf5x_common/Makefile.dep
include $(RIOTCPU)/cortexm_common/Makefile.dep

View File

@ -10,6 +10,18 @@ ifneq (,$(filter nrf52811xxaa nrf52820xxaa nrf52833xxaa nrf52840xxaa,$(CPU_MODEL
FEATURES_PROVIDED += radio_nrf802154
endif
# crypto features
ifneq (,$(filter nrf52840xxaa,$(CPU_MODEL)))
FEATURES_PROVIDED += periph_hash_sha_1
FEATURES_PROVIDED += periph_hash_sha_224
FEATURES_PROVIDED += periph_hash_sha_256
FEATURES_PROVIDED += periph_hash_sha_512
FEATURES_PROVIDED += periph_hmac_sha_256
FEATURES_PROVIDED += periph_cipher_aes_128_cbc
FEATURES_PROVIDED += periph_ecc_p192r1
FEATURES_PROVIDED += periph_ecc_p256r1
endif
ifeq (,$(filter nrf52832%,$(CPU_MODEL)))
FEATURES_PROVIDED += periph_uart_nonblocking
endif
@ -33,6 +45,10 @@ ifneq (,$(filter nrf52811% nrf52820% nrf52833% nrf52840%,$(CPU_MODEL)))
FEATURES_PROVIDED += ble_phy_coded
endif
ifneq (,$(filter nrf52840%,$(CPU_MODEL)))
FEATURES_PROVIDED += periph_cryptocell_310
endif
FEATURES_PROVIDED += ble_adv_ext
include $(RIOTCPU)/nrf5x_common/Makefile.features

View File

@ -12,6 +12,61 @@ config MODULE_SAUL_NRF_VDDH
depends on HAS_PERIPH_ADC
select MODULE_PERIPH_ADC
config MODULE_PERIPH_CRYPTOCELL_310
bool
depends on HAS_PERIPH_CRYPTOCELL_310
select PACKAGE_DRIVER_CRYPTOCELL_310
# Asymmetric Crypto Peripheral
config MODULE_PERIPH_ECC_P192R1
bool
depends on HAS_PERIPH_ECC_P192R1
select MODULE_PERIPH_CRYPTOCELL_310
select MODULE_PSA_CRYPTOCELL_310_ECC_P192
config MODULE_PERIPH_ECC_P256R1
bool
depends on HAS_PERIPH_ECC_P256R1
select MODULE_PERIPH_CRYPTOCELL_310
select MODULE_PSA_CRYPTOCELL_310_ECC_P256
# Hash Related Symbols
config MODULE_PERIPH_HASH_SHA_1
bool
depends on HAS_PERIPH_HASH_SHA_1
select MODULE_PERIPH_CRYPTOCELL_310
select MODULE_PSA_CRYPTOCELL_310_HASHES_SHA1
config MODULE_PERIPH_HASH_SHA_224
bool
depends on HAS_PERIPH_HASH_SHA_224
select MODULE_PERIPH_CRYPTOCELL_310
select MODULE_PSA_CRYPTOCELL_310_HASHES_SHA224
config MODULE_PERIPH_HASH_SHA_256
bool
depends on HAS_PERIPH_HASH_SHA_256
select MODULE_PERIPH_CRYPTOCELL_310
select MODULE_PSA_CRYPTOCELL_310_HASHES_SHA256
config MODULE_PERIPH_HASH_SHA_512
bool
depends on HAS_PERIPH_HASH_SHA_512
select MODULE_PERIPH_CRYPTOCELL_310
select MODULE_PSA_CRYPTOCELL_310_HASHES_SHA512
config MODULE_PERIPH_CIPHER_AES_128_CBC
bool
depends on HAS_PERIPH_CIPHER_AES_128_CBC
select MODULE_PERIPH_CRYPTOCELL_310
select MODULE_PSA_CRYPTOCELL_310_AES_CBC
config MODULE_PERIPH_HMAC_SHA_256
bool
depends on HAS_PERIPH_HMAC_SHA_256
select MODULE_PERIPH_CRYPTOCELL_310
select MODULE_PSA_CRYPTOCELL_310_HMAC
endif # TEST_KCONFIG
config HAVE_SAUL_NRF_VDDH

View File

@ -0,0 +1,39 @@
ifneq (,$(filter periph_ecc_p192r1,$(USEMODULE)))
USEPKG += driver_cryptocell_310
USEMODULE += psa_cryptocell_310_ecc_p192
endif
ifneq (,$(filter periph_ecc_p256r1,$(USEMODULE)))
USEPKG += driver_cryptocell_310
USEMODULE += psa_cryptocell_310_ecc_p256
endif
ifneq (,$(filter periph_hash_sha_1,$(USEMODULE)))
USEPKG += driver_cryptocell_310
USEMODULE += psa_cryptocell_310_hashes_sha1
endif
ifneq (,$(filter periph_hash_sha_224,$(USEMODULE)))
USEPKG += driver_cryptocell_310
USEMODULE += psa_cryptocell_310_hashes_sha224
endif
ifneq (,$(filter periph_hash_sha_256,$(USEMODULE)))
USEPKG += driver_cryptocell_310
USEMODULE += psa_cryptocell_310_hashes_sha256
endif
ifneq (,$(filter periph_hash_sha_512,$(USEMODULE)))
USEPKG += driver_cryptocell_310
USEMODULE += psa_cryptocell_310_hashes_sha512
endif
ifneq (,$(filter periph_cipher_aes_128_cbc,$(USEMODULE)))
USEPKG += driver_cryptocell_310
USEMODULE += psa_cryptocell_310_aes_cbc
endif
ifneq (,$(filter periph_hmac_sha_256,$(USEMODULE)))
USEPKG += driver_cryptocell_310
USEMODULE += psa_cryptocell_310_hmac
endif

View File

@ -162,3 +162,9 @@ noe
# NWE (Negative Write Enable) ==> NEW
nwe
# rsource (used to include Kconfig files) ==> resource, source
rsource
# SHS (abbreviation for Secure Hash Standard) => SSH, NHS
shs

View File

@ -0,0 +1,851 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
width="500"
height="266"
id="svg1869"
sodipodi:docname="riot-psa-structure.svg"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
id="namedview1871"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="1.9539249"
inkscape:cx="187.82707"
inkscape:cy="175.28821"
inkscape:window-width="2556"
inkscape:window-height="1396"
inkscape:window-x="0"
inkscape:window-y="20"
inkscape:window-maximized="1"
inkscape:current-layer="gnrc-detail" />
<title
id="title1749">RIOT's GNRC Network Stack</title>
<metadata
id="metadata1751">
<rdf:RDF>
<cc:Work
rdf:about="Provides a general overview over RIOT's GNRC Network Stack">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>RIOT's GNRC Network Stack</dc:title>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
<dc:creator>
<cc:Agent>
<dc:title>Cenk Gündoğan</dc:title>
</cc:Agent>
<cc:Agent>
<dc:title>Martine Lenders</dc:title>
</cc:Agent>
</dc:creator>
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<defs
id="defs1779">
<style
type="text/css"
id="style1753"><![CDATA[
@font-face {
font-family: 'Miso';
font-style: normal;
font-weight: normal;
src: url('miso.eot'); /* IE 9 Compatibility Mode */
src: url('miso.eot?#iefix') format('embedded-opentype'), /* IE < 9 */
url('data:application/x-font-woff;charset=utf-8;base64, \
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 \
') format('woff'), /* Firefox >= 3.6, any other modern browser */
url('miso.ttf') format('truetype'), /* Safari, Android, iOS */
url('miso.svg#Miso') format('svg'); /* Chrome < 4, Legacy iOS */
}
.modbox-text {
line-height: 125%;
fill: #ffffff;
font-family: 'Miso';
font-size: 28px;
text-anchor: middle;
}
.modbox {
fill: #275a4b;
stroke: #3fa687;
stroke-linecap: round;
stroke-linejoin: round;
stroke-miterlimit: 4;
stroke-width: 3;
}
.outer-text {
line-height: 125%;
fill: #3fa687;
font-family: 'Miso';
font-size: 32px;
text-anchor: middle;
}
.outer-text-netapi {
line-height: 125%;
fill: #3fa687;
font-family: 'Miso';
font-size: 28px;
text-anchor: start;
}
.outer-stroke {
fill: none;
stroke: #3fa687;
stroke-linecap: round;
stroke-linejoin: miter;
stroke-miterlimit: 4;
stroke-width: 3;
}
#gnrc-detail-sock {
fill: none;
stroke: url(#outer-gradient-sock);
stroke-linecap: round;
stroke-linejoin: miter;
stroke-miterlimit: 4;
stroke-width: 3;
}
#gnrc-detail-netdev {
fill: none;
stroke: url(#outer-gradient-netdev);
stroke-linecap: round;
stroke-linejoin: miter;
stroke-miterlimit: 4;
stroke-width: 3;
}
.outer-stroke-dashed {
fill: none;
stroke: #3fa687;
stroke-dasharray: 9, 9;
stroke-linecap: round;
stroke-linejoin: miter;
stroke-miterlimit: 4;
stroke-width: 3;
}
.outer-stroke-dotted {
fill: none;
stroke: #3fa687;
stroke-dasharray: 1, 5;
stroke-linecap: round;
stroke-linejoin: miter;
stroke-miterlimit: 4;
stroke-width: 3;
}
.outer-stroke-arrow {
fill: none;
marker-start: url(#arrow-start);
marker-end: url(#arrow-end);
stroke: #3fa687;
stroke-linecap: round;
stroke-linejoin: miter;
stroke-miterlimit: 4;
stroke-width: 3;
}
.outer-arrow-head {
fill: #3fa687;
fill-rule: evenodd;
stroke: #3fa687;
stroke-width: 1pt;
}
]]></style>
<linearGradient
id="outer-gradient-sock"
x1="-0.44030017"
y1="-5.1101503"
x2="-0.44030017"
y2="107.31316"
gradientTransform="scale(3.4067669,0.29353344)"
gradientUnits="userSpaceOnUse">
<stop
style="stop-color: #3fa687; stop-opacity: 0;"
offset="0"
id="stop1755" />
<stop
style="stop-color: #3fa687; stop-opacity: 0;"
offset="0.1"
id="stop1757" />
<stop
style="stop-color: #3fa687; stop-opacity: 1;"
offset="0.9"
id="stop1759" />
<stop
style="stop-color: #3fa687; stop-opacity: 1;"
offset="1"
id="stop1761" />
</linearGradient>
<linearGradient
id="outer-gradient-netdev"
x1="-0.44030017"
y1="1221.3259"
x2="-0.44030017"
y2="1333.7491"
gradientTransform="scale(3.4067669,0.29353344)"
gradientUnits="userSpaceOnUse">
<stop
style="stop-color: #3fa687; stop-opacity: 1;"
offset="0"
id="stop1764" />
<stop
style="stop-color: #3fa687; stop-opacity: 1;"
offset="0.1"
id="stop1766" />
<stop
style="stop-color: #3fa687; stop-opacity: 0;"
offset="0.9"
id="stop1768" />
<stop
style="stop-color: #3fa687; stop-opacity: 0;"
offset="1"
id="stop1770" />
</linearGradient>
<marker
style="overflow:visible"
id="arrow-start"
orient="auto">
<path
class="outer-arrow-head"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
transform="matrix(0.2,0,0,0.2,1.2,0)"
id="path1773" />
</marker>
<marker
style="overflow:visible"
id="arrow-end"
orient="auto">
<path
class="outer-arrow-head"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
id="path1776" />
</marker>
</defs>
<g
id="gnrc-detail"
transform="matrix(0.75,0,0,0.75,3.75,0)">
<g
id="g8922">
<rect
id="gnrc-sock-box"
class="modbox"
x="9.759263"
y="17.349091"
rx="7.0792012"
ry="4.0499377"
width="637.12817"
height="50.624222"
style="stroke-width:2.70911;stroke-dasharray:none" />
<text
id="gnrc-sock-label"
class="modbox-text"
x="328.18332"
y="51.050667"><tspan
id="tspan1785">PSA Crypto</tspan></text>
</g>
<g
id="g3901"
transform="matrix(0.99993339,0,0,1.0321558,-0.71650498,84.465735)"
style="stroke-width:2.62489;stroke-dasharray:none">
<rect
id="gnrc-sock-box-6"
class="modbox"
x="10.476466"
y="0.47646618"
rx="7.0796728"
ry="3.9237654"
width="637.17059"
height="49.04707"
style="fill:#275a4b;stroke:#3fa687;stroke-width:2.62489;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7"
class="modbox-text"
x="328.92175"
y="32"
style="font-size:28px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#ffffff;stroke-width:2.62489;stroke-dasharray:none"><tspan
id="tspan1785-5"
style="stroke-width:2.62489;stroke-dasharray:none">Key Management and Location Dispatch</tspan></text>
</g>
<g
id="g3896"
transform="translate(43.403416,87.323162)">
<rect
id="gnrc-sock-box-6-5"
class="modbox"
x="293.2406"
y="65.227448"
rx="3.4473193"
ry="4.052392"
width="310.25876"
height="50.6549"
style="fill:#275a4b;stroke:#3fa687;stroke-width:2.67843;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7-6"
class="modbox-text"
x="448.90601"
y="97.554901"
style="font-size:28px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#ffffff"><tspan
id="tspan1785-5-2">Algorithm Dispatch</tspan></text>
</g>
<g
id="g3896-2"
transform="matrix(0.99996209,0,0,1.0088791,43.420411,154.13341)">
<rect
id="gnrc-sock-box-6-5-0"
class="modbox"
x="293.23471"
y="65.450356"
rx="3.4474499"
ry="4.016727"
width="310.27051"
height="50.209087"
style="fill:#275a4b;stroke:#3fa687;stroke-width:2.66667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7-6-23"
class="modbox-text"
x="448.90601"
y="97.554901"
style="font-size:28px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#ffffff"><tspan
id="tspan1785-5-2-75">Spec. Algorithm API</tspan></text>
</g>
<g
id="g7406"
transform="matrix(0.99996307,0,0,1.0086479,0.00608848,0.69035637)">
<rect
id="gnrc-sock-box-6-5-1"
class="modbox"
x="9.7380409"
y="150.56415"
rx="3.4474499"
ry="4.016727"
width="310.27051"
height="50.209087"
style="fill:#275a4b;stroke:#3fa687;stroke-width:2.66667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7-6-2"
class="modbox-text"
x="164.89879"
y="182.05269"
style="font-size:28px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#ffffff"><tspan
id="tspan1785-5-2-7">SE Dispatch</tspan></text>
</g>
<g
id="g5505"
transform="matrix(1.0002158,0,0,0.98547915,-282.22812,86.706483)">
<rect
id="gnrc-sock-box-6-5-1-9"
class="modbox"
x="291.89359"
y="135.4252"
rx="0.98559189"
ry="4.1146121"
width="88.70327"
height="51.432655"
style="fill:#275a4b;stroke:#3fa687;stroke-width:2.66667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7-6-2-3"
class="modbox-text"
x="336.57822"
y="170.04283"
style="font-size:28px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#ffffff"><tspan
id="tspan1785-5-2-7-6">SE API</tspan></text>
</g>
<g
id="g5505-0"
transform="matrix(1.0002158,0,0,0.98547915,-172.47439,86.706483)">
<rect
id="gnrc-sock-box-6-5-1-9-6"
class="modbox"
x="291.89359"
y="135.4252"
rx="0.98559189"
ry="4.1146121"
width="88.70327"
height="51.432655"
style="fill:#275a4b;stroke:#3fa687;stroke-width:2.66667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7-6-2-3-2"
class="modbox-text"
x="336.57822"
y="170.04283"
style="font-size:28px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#ffffff"><tspan
id="tspan1785-5-2-7-6-6">SE API</tspan></text>
</g>
<g
id="g5505-1"
transform="matrix(1.0002158,0,0,0.98547915,-62.864627,86.706483)">
<rect
id="gnrc-sock-box-6-5-1-9-8"
class="modbox"
x="291.89359"
y="135.4252"
rx="0.98559189"
ry="4.1146121"
width="88.70327"
height="51.432655"
style="fill:#275a4b;stroke:#3fa687;stroke-width:2.66667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7-6-2-3-7"
class="modbox-text"
x="336.57822"
y="170.04283"
style="font-size:28px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#ffffff"><tspan
id="tspan1785-5-2-7-6-9">SE API</tspan></text>
</g>
<rect
id="gnrc-sock-box-6-5-1-9-2"
class="modbox"
x="9.7284555"
y="287.78241"
rx="0.98580456"
ry="4.0548644"
width="88.722412"
height="50.68581"
style="fill:#b6e0d3;fill-opacity:1;stroke:#3fa687;stroke-width:2.64752;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7-6-2-3-8"
class="modbox-text"
x="54.020325"
y="324.29523"
style="font-size:27.799px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#275a4b;fill-opacity:1;stroke-width:0.99282"
transform="scale(1.0074492,0.99260593)"><tspan
id="tspan1785-5-2-7-6-97"
style="fill:#275a4b;fill-opacity:1;stroke-width:0.99282">SE1 Drv</tspan></text>
<rect
id="gnrc-sock-box-6-5-1-9-6-6"
class="modbox"
x="119.48219"
y="287.78241"
rx="0.98580456"
ry="4.0548644"
width="88.722412"
height="50.68581"
style="fill:#b6e0d3;fill-opacity:1;stroke:#3fa687;stroke-width:2.64752;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7-6-2-3-2-1"
class="modbox-text"
x="162.96252"
y="324.29523"
style="font-size:27.799px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#275a4b;fill-opacity:1;stroke-width:0.99282"
transform="scale(1.0074492,0.99260593)"><tspan
id="tspan1785-5-2-7-6-6-2"
style="fill:#275a4b;fill-opacity:1;stroke-width:0.99282">SE2 Drv</tspan></text>
<rect
id="gnrc-sock-box-6-5-1-9-8-3"
class="modbox"
x="229.09195"
y="287.78241"
rx="0.98580456"
ry="4.0548644"
width="88.722412"
height="50.68581"
style="fill:#b6e0d3;fill-opacity:1;stroke:#3fa687;stroke-width:2.64752;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7-6-2-3-7-1"
class="modbox-text"
x="271.76184"
y="324.29523"
style="font-size:27.799px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#275a4b;fill-opacity:1;stroke-width:0.99282"
transform="scale(1.0074492,0.99260593)"><tspan
id="tspan1785-5-2-7-6-9-9"
style="fill:#275a4b;fill-opacity:1;stroke-width:0.99282">SE3 Drv</tspan></text>
<rect
id="gnrc-sock-box-6-5-1-9-6-6-7"
class="modbox"
x="337.05817"
y="287.77283"
rx="1.6380999"
ry="4.0533733"
width="147.429"
height="50.667171"
style="fill:#b6e0d3;fill-opacity:1;stroke:#3fa687;stroke-width:2.66617;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7-6-2-3-2-1-8"
class="modbox-text"
x="410.22644"
y="322.06619"
style="font-size:27.9947px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#275a4b;fill-opacity:1;stroke-width:2.66617;stroke-dasharray:none"
transform="scale(1.0001922,0.99980782)"><tspan
id="tspan1785-5-2-7-6-6-2-4"
style="fill:#275a4b;fill-opacity:1;stroke-width:2.66617;stroke-dasharray:none">HW Drv</tspan></text>
<rect
id="gnrc-sock-box-6-5-1-9-6-6-7-0"
class="modbox"
x="499.10678"
y="287.7822"
rx="1.6380999"
ry="4.0533733"
width="147.429"
height="50.667171"
style="fill:#b6e0d3;fill-opacity:1;stroke:#3fa687;stroke-width:2.66617;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7-6-2-3-2-1-8-6"
class="modbox-text"
x="572.2439"
y="322.07556"
style="font-size:27.9947px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#275a4b;fill-opacity:1;stroke-width:0.999811"
transform="scale(1.0001922,0.99980782)"><tspan
id="tspan1785-5-2-7-6-6-2-4-1"
style="fill:#275a4b;fill-opacity:1;stroke-width:0.999811">SW Library</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 50 KiB

View File

@ -0,0 +1,116 @@
# This has to be the absolute path to the RIOT base directory:
RIOTBASE ?= $(CURDIR)/../..
APPLICATION = example_psa_crypto
BOARD ?= native
# Necessary configurations when using Kconfig dependency resolution
# The file `app.config.test` is always used for the build configuration.
# The config files below are only added if needed.
ifeq (1, $(TEST_KCONFIG))
ifeq (1, $(SECURE_ELEMENT))
CFLAGS += -DSECURE_ELEMENT # Application specific (not needed by PSA)
CFLAGS += -DCUSTOM_ATCA_PARAMS # Application specific (not needed by PSA)
INCLUDES += -I$(APPDIR) # Application specific (not needed by PSA)
KCONFIG_ADD_CONFIG += $(APPDIR)/app.config.test.se
else ifeq (2, $(SECURE_ELEMENT))
CFLAGS += -DSECURE_ELEMENT # Application specific (not needed by PSA)
CFLAGS += -DMULTIPLE_SE # Application specific (not needed by PSA)
CFLAGS += -DCUSTOM_ATCA_PARAMS # Application specific (not needed by PSA)
INCLUDES += -I$(APPDIR)
KCONFIG_ADD_CONFIG += $(APPDIR)/app.config.test.multi_se
else ifdef CUSTOM_BACKEND
KCONFIG_ADD_CONFIG += $(APPDIR)/app.config.test.base
KCONFIG_ADD_CONFIG += $(APPDIR)/app.config.test.custom
else
KCONFIG_ADD_CONFIG += $(APPDIR)/app.config.test.base
endif
else
USEMODULE += ztimer
USEMODULE += ztimer_usec
USEMODULE += psa_crypto
# Hashes are needed for ECDSA operations (including secure elements), which
# is why we always build them
USEMODULE += psa_hash
USEMODULE += psa_hash_sha_256
ifeq (1, $(SECURE_ELEMENT))
# When using a secure element, the type is required.
# Also you can specify the number of key slots required to store keys.
CFLAGS += -DSECURE_ELEMENT # Application specific (not needed by PSA)
CFLAGS += -DCUSTOM_ATCA_PARAMS # Application specific (not needed by PSA)
INCLUDES += -I$(APPDIR) # Application specific (not needed by PSA)
CFLAGS += -DCONFIG_PSA_PROTECTED_KEY_COUNT=4
CFLAGS += -DCONFIG_PSA_SINGLE_KEY_COUNT=1
USEMODULE += psa_secure_element
USEMODULE += psa_secure_element_ateccx08a
USEMODULE += psa_secure_element_ateccx08a_ecc_p256
else ifeq (2, $(SECURE_ELEMENT))
CFLAGS += -DSECURE_ELEMENT # Application specific (not needed by PSA)
CFLAGS += -DMULTIPLE_SE # Application specific (not needed by PSA)
CFLAGS += -DCUSTOM_ATCA_PARAMS # Application specific (not needed by PSA)
INCLUDES += -I$(APPDIR) # Application specific (not needed by PSA)
CFLAGS += -DCONFIG_PSA_MAX_SE_COUNT=2
CFLAGS += -DCONFIG_PSA_PROTECTED_KEY_COUNT=8
CFLAGS += -DCONFIG_PSA_SINGLE_KEY_COUNT=2
USEMODULE += psa_secure_element
USEMODULE += psa_secure_element_multiple
USEMODULE += psa_secure_element_ateccx08a
USEMODULE += psa_secure_element_ateccx08a_ecc_p256
else ifdef CUSTOM_BACKEND
# Necessary configuration when using Make dependency resolution
# This first part chooses the operation. If nothing else es specified,
# a default backend is built depending on the platform capabilities.
USEMODULE += psa_cipher
USEMODULE += psa_cipher_aes_128_cbc
USEMODULE += psa_mac
USEMODULE += psa_mac_hmac_sha_256
USEMODULE += psa_asymmetric
USEMODULE += psa_asymmetric_ecc_p256r1
# If you want to use a custom backend, you need to do it this way.
USEMODULE += psa_cipher_aes_128_cbc_custom_backend
USEMODULE += psa_cipher_aes_128_cbc_backend_riot # force custom backend
USEMODULE += psa_mac_hmac_sha_256_custom_backend
USEMODULE += psa_mac_hmac_sha_256_backend_riot # force custom backend
USEMODULE += psa_hash_sha_256_custom_backend
USEMODULE += psa_hash_sha_256_backend_riot
USEMODULE += psa_asymmetric_ecc_p256r1_custom_backend
USEMODULE += psa_asymmetric_ecc_p256r1_backend_microecc # force custom backend
else
# Necessary configuration when using Make dependency resolution
# This part only chooses the operation. If nothing else es specified,
# a default backend is built depending on the platform capabilities.
USEMODULE += psa_cipher
USEMODULE += psa_cipher_aes_128_cbc
USEMODULE += psa_mac
USEMODULE += psa_mac_hmac_sha_256
USEMODULE += psa_asymmetric
USEMODULE += psa_asymmetric_ecc_p256r1
endif
ifndef SECURE_ELEMENT
CFLAGS += -DCONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=1
CFLAGS += -DCONFIG_PSA_SINGLE_KEY_COUNT=3
endif
endif
ifndef SECURE_ELEMENT
# The software implementations need a larger stack, so we increase the stack size.
CFLAGS += -DTHREAD_STACKSIZE_MAIN=\(12*THREAD_STACKSIZE_DEFAULT\)
endif
SHOULD_RUN_KCONFIG :=
include $(RIOTBASE)/Makefile.include

View File

@ -0,0 +1,28 @@
BOARD_INSUFFICIENT_MEMORY := \
arduino-duemilanove \
arduino-leonardo \
arduino-mega2560 \
arduino-nano \
arduino-uno \
atmega328p \
atmega328p-xplained-mini \
atmega8 \
bluepill-stm32f030c8 \
i-nucleo-lrwan1 \
nucleo-f030r8 \
nucleo-f031k6 \
nucleo-f042k6 \
nucleo-f303k8 \
nucleo-f334r8 \
nucleo-l011k4 \
nucleo-l031k6 \
nucleo-l053r8 \
samd10-xmini \
slstk3400a \
stk3200 \
stm32f030f4-demo \
stm32f0discovery \
stm32g0316-disco \
stm32l0538-disco \
waspmote-pro \
#

View File

@ -0,0 +1,102 @@
# Example Applications for PSA Crypto
This example application is supposed to show two things:
1. How to use basic functions of the PSA Crypto API
2. How to configure the implementation with Kconfig dependency resolution vs. Make dependency resolution
## Basic usage of PSA Crypto
There are three example operations:
- AES 128 CBC
- HMAC SHA256
- ECDSA with a P256 curve
Each comes in its own sourcefile called `example_<operation>.c`. To see which functions to call to perform each operations, please read the code.
The application measures the processing times of the example operations. The table below shows the expected runtime values
for software and hardware backends as well as secure elements, measured on the nRF52840dk (this is only to show the expected difference, values will differ on other platforms).
| Operations | Backends | Runtime \[us\] |
|-------------|----------------|------------------|
| HMAC SHA256 | CryptoCell 310 | 282 |
| | RIOT Hashes | 468 |
| | ATECC608A | 56376 |
| AES 128 CBC | CryptoCell 310 | 140 |
| | RIOT Cipher | 295 |
| | ATECC608A | 68819 |
| ECDSA P256 | CryptoCell 310 | 60931 |
| | Micro-ECC | 522424 |
| | ATECC608A | 285542 |
## Configuration of the API
There are two ways to configure the API: module selection via Kconfig and module selection
via Makefiles.
To see which modules should be chosen for each configuration, please read the Makefile and
the `app.config.test.*` files.
### Kconfig
> **NOTE:** In this application all the configurations are in separate app.config files
> for demonstration purposes. You can also write all configs into one file or choose them
> via `menuconfig`.
> To access the GUI, run `TEST_KCONFIG=1 BOARD=<your board> make menuconfig`.
When building the application with the `TEST_KCONFIG=1` option, the first config file parsed by the build system is `app.config.test`. This selects the PSA Crypto module and other modules our application needs (e.g. ztimer). If you need cryptographic keys, you can specify the number of key slots needed for key storage (the default is set to 5).
The graph below shows how the `app.config` files in this application are included.
Selections in `app.config.test` are always applied.
The others are only added, if you specify the corresponding build option.
```mermaid
flowchart TD;
app.config.test -- default --> app.config.test.base;
app.config.test.base -- CUSTOM_BACKEND=1 --> app.config.test.custom;
app.config.test -- SECURE_ELEMENT=1 --> app.config.test.se;
app.config.test -- SECURE_ELEMENT=2 --> app.config.test.multi_se;
```
If you build this without specifying anything else, the symbols in `app.config.test.base`
are added and PSA Crypto will automatically choose a default crypto backend depending on the platform you're building for.
For example when your platform is `native`, software implementations are built.
When you specify `BOARD=nrf52840dk`, the hardware accelerator of the board will be built.
If you want to force a custom backend, you can specify that in the Kconfig file. This application already contains the configuration for a custom backend (see `app.config.test.custom`), which will be added to the application build when you define `CUSTOM_BACKEND=1`.
Instead of or in addition to the default and custom implementations you can use a secure element as a backend (see Section [Using Secure Elements](#using-secure-elements]).
Secure elements are independent of the other backends. In this application, when you
choose secure elements, they are built instead of the other backends.
Please note that the build options `CUSTOM_BACKEND` and `SECURE_ELEMENT` only apply to this specific application and have nothing to do with the PSA implementation.
### Make
All the configurations in the Kconfig files can also be applied using Make dependency resolution. The Makefile contains all the modules that must be selected when building the different configurations.
They can all be built as described above, but *without* defining TEST_KCONFIG.
To prevent conflicts when building this application multiple times with different backends, it is best to remove the `bin` directory in between builds.
## Using Secure Elements
> **NOTE:**
> Currently this implementation only supports Microchip ATECCX08A devices. Those devices need to be configured and locked to be able to correctly use them.
> This implementation assumes that you have done that and that you know your device's configuration.
You can build this app either with one secure element or two secure elements (`SECURE_ELEMENT=1` or `SECURE_ELEMENT=2`). To be able to use your device, make sure, you've completed the following procedure.
In the application folder you can find a file called `custom_atca_params.h`, which overwrites the device parameters in `atca_params.h` in the cryptoauthlib package folder.
To use more than one secure element, you need to specify device parameters for both of them.
This application assumes that you connect two devices with different I2C addresses on the same I2C bus.
Alternatively you can connect two devices with the same address on separate buses.
You can modify `custom_atca_params.h` according to your device configurations and requirements.
For PSA Crypto, you also need to define a location value. Here these are defined as `PSA_ATCA_LOCATION_DEV0` and `PSA_ATCA_LOCATION_DEV1`. They can be any value between `PSA_KEY_LOCATION_SE_MIN` and `PSA_KEY_LOCATION_SE_MAX`.
A special value is `PSA_KEY_LOCATION_PRIMARY_SECURE_ELEMENT`, which can be used when only one secure element is needed.
Below the `ATCA_PARAMS` definitions, you can see the slot configurations.
Here you need to specify for each connected secure element what kind of key can be stored in which slot, and whether a slot is already occupied. The structure is declared in `pkg/cryptoauthlib/include/atca.h` and contains the following elements:
1. `key_type_allowed` (takes `psa_key_type_t`)
2. `key_persistent` (is 0, can be ignored for now, since PSA does not yet support persistent storage)
3. `slot_occupied` (should be 0 at start up, PSA will use this to mark slots as occupied)
The list in `custom_atca_params.h` contains an example configuration. If your device configuration is not compatible, you'll need to change the values as necessary.
This is required, so the implementation can allocate free key slots and can generate and import new keys. If the device configuration does not match the values in the list or if your key slots are not writeable, you will get execution errors.
The current implementation does not support the use of keys that are already stored on the device.
## Note
If you need more information about the build options, please refer to the API documentation.

View File

@ -0,0 +1,6 @@
CONFIG_MODULE_PSA_CRYPTO=y
CONFIG_MODULE_PSA_HASH=y
CONFIG_MODULE_PSA_HASH_SHA_256=y
CONFIG_ZTIMER_USEC=y

View File

@ -0,0 +1,11 @@
CONFIG_MODULE_PSA_CIPHER=y
CONFIG_MODULE_PSA_CIPHER_AES_128_CBC=y
CONFIG_MODULE_PSA_MAC=y
CONFIG_MODULE_PSA_MAC_HMAC_SHA_256=y
CONFIG_MODULE_PSA_ASYMMETRIC=y
CONFIG_MODULE_PSA_ASYMMETRIC_ECC_P256R1=y
CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=1
CONFIG_PSA_SINGLE_KEY_COUNT=3

View File

@ -0,0 +1,8 @@
# force software backends
CONFIG_MODULE_PSA_CIPHER_AES_128_CBC_BACKEND_RIOT=y
CONFIG_MODULE_PSA_HASH_SHA_256_BACKEND_RIOT=y
CONFIG_MODULE_PSA_MAC_HMAC_SHA_256_BACKEND_RIOT=y
CONFIG_MODULE_PSA_ASYMMETRIC_ECC_P256R1_BACKEND_MICROECC=y
CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=1
CONFIG_PSA_SINGLE_KEY_COUNT=3

View File

@ -0,0 +1,9 @@
CONFIG_MODULE_PSA_SECURE_ELEMENT=y
CONFIG_MODULE_PSA_SECURE_ELEMENT_ATECCX08A=y
CONFIG_MODULE_PSA_SECURE_ELEMENT_ATECCX08A_ECC_P256=y
CONFIG_MODULE_PSA_SECURE_ELEMENT_MULTIPLE=y
CONFIG_PSA_MAX_SE_COUNT=2
CONFIG_PSA_PROTECTED_KEY_COUNT=8
CONFIG_PSA_SINGLE_KEY_COUNT=2

View File

@ -0,0 +1,6 @@
CONFIG_MODULE_PSA_SECURE_ELEMENT=y
CONFIG_MODULE_PSA_SECURE_ELEMENT_ATECCX08A=y
CONFIG_MODULE_PSA_SECURE_ELEMENT_ATECCX08A_ECC_P256=y
CONFIG_PSA_PROTECTED_KEY_COUNT=4
CONFIG_PSA_SINGLE_KEY_COUNT=1

View File

@ -0,0 +1,125 @@
/*
* Copyright (C) 2023 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup examples
* @{
*
* @file
* @brief Example custom atca_params.h file to use multiple ATECC608A
* secure elements as backends for PSA Crypto
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef CUSTOM_ATCA_PARAMS_H
#define CUSTOM_ATCA_PARAMS_H
#include "cryptoauthlib.h"
#include "psa/crypto.h"
#ifdef __cplusplus
extern "C" {
#endif
#define PSA_ATCA_LOCATION_DEV0 (PSA_KEY_LOCATION_PRIMARY_SECURE_ELEMENT)
#define ATCA_PARAM_I2C_DEV0 (I2C_DEV(0)) /*!< Change this to the bus you want to use */
#define ATCA_PARAM_ADDR_DEV0 (0xC0) /*!< Change this to your first device's address */
#define ATCA_DEVTYPE_DEV0 (ATECC608A)
#define ATCA_RX_RETRIES (20)
#ifdef MULTIPLE_SE
#define PSA_ATCA_LOCATION_DEV1 (PSA_KEY_LOCATION_SE_MIN)
#define ATCA_PARAM_I2C_DEV1 (I2C_DEV(0)) /*!< Change this to the bus you want to use */
#define ATCA_PARAM_ADDR_DEV1 (0xCC) /*!< Change this to your second device's address */
#define ATCA_DEVTYPE_DEV1 (ATECC608A)
#define ATCA_PARAMS { .atca_loc = PSA_ATCA_LOCATION_DEV0,\
.cfg = {\
.iface_type = ATCA_I2C_IFACE, \
.devtype = ATCA_DEVTYPE_DEV0, \
.atcai2c.address = ATCA_PARAM_ADDR_DEV0, \
.atcai2c.bus = ATCA_PARAM_I2C_DEV0, \
.atcai2c.baud = -1, /**< Not used in RIOT */ \
.wake_delay = 1500, \
.rx_retries = ATCA_RX_RETRIES } \
}, \
{ .atca_loc = PSA_ATCA_LOCATION_DEV1,\
.cfg = {\
.iface_type = ATCA_I2C_IFACE, \
.devtype = ATCA_DEVTYPE_DEV1, \
.atcai2c.address = ATCA_PARAM_ADDR_DEV1, \
.atcai2c.bus = ATCA_PARAM_I2C_DEV1, \
.atcai2c.baud = -1, /**< Not used in RIOT */ \
.wake_delay = 1500, \
.rx_retries = ATCA_RX_RETRIES } \
}
#else
#define ATCA_PARAMS { .atca_loc = PSA_ATCA_LOCATION_DEV0,\
.cfg = {\
.iface_type = ATCA_I2C_IFACE, \
.devtype = ATCA_DEVTYPE_DEV0, \
.atcai2c.address = ATCA_PARAM_ADDR_DEV0, \
.atcai2c.bus = ATCA_PARAM_I2C_DEV0, \
.atcai2c.baud = -1, /**< Not used in RIOT */ \
.wake_delay = 1500, \
.rx_retries = ATCA_RX_RETRIES } \
}
#endif /* MULTIPLE_SE */
#define ATCA_SLOTS_DEV0 { \
{ PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
{ PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
{ PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
{ PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
{ PSA_KEY_TYPE_AES, 0, 0 }, \
{ PSA_KEY_TYPE_HMAC, 0, 0 }, \
{ PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
{ 0, 1, 1 }, \
{ 0, 0, 0 }, \
{ PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
{ PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
{ PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
{ PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
{ PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
{ 0, 0, 0 }, \
{ 0, 0, 0 }}
#ifdef MULTIPLE_SE
#define ATCA_SLOTS_DEV1 { \
{ PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
{ PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
{ PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
{ PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
{ PSA_KEY_TYPE_AES, 0, 0 }, \
{ PSA_KEY_TYPE_HMAC, 0, 0 }, \
{ PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
{ 0, 1, 1 }, \
{ 0, 0, 0 }, \
{ PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
{ PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
{ PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
{ PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
{ PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
{ 0, 0, 0 }, \
{ 0, 0, 0 }}
#endif
#ifdef MULTIPLE_SE
#define ATCA_CONFIG_LIST { ATCA_SLOTS_DEV0 }, \
{ ATCA_SLOTS_DEV1 }
#else
#define ATCA_CONFIG_LIST { ATCA_SLOTS_DEV0 }
#endif
#ifdef __cplusplus
}
#endif
#endif /* CUSTOM_ATCA_PARAMS_H */
/** @} */

View File

@ -0,0 +1,131 @@
/*
* Copyright (C) 2022 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup examples
* @{
*
* @brief Example functions for AES CBC encryption with PSA Crypto
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include <stdio.h>
#include <stdint.h>
#include "psa/crypto.h"
#define AES_128_KEY_SIZE (16)
#define AES_256_KEY_SIZE (32)
static const uint8_t KEY_128[] = {
0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
};
static uint8_t PLAINTEXT[] = {
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51
};
static uint8_t PLAINTEXT_LEN = 32;
/**
* @brief Example function to perform an AES-128 CBC encryption and decryption
* with the PSA Crypto API.
*
* @return psa_status_t
*/
psa_status_t example_cipher_aes_128(void)
{
psa_status_t status = PSA_ERROR_DOES_NOT_EXIST;
psa_key_id_t key_id = 0;
psa_key_attributes_t attr = psa_key_attributes_init();
psa_key_usage_t usage = PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT;
size_t encr_output_size = PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_AES,
PSA_ALG_CBC_NO_PADDING, PLAINTEXT_LEN);
uint8_t cipher_out[encr_output_size];
uint8_t plain_out[sizeof(PLAINTEXT)];
size_t output_len = 0;
psa_set_key_algorithm(&attr, PSA_ALG_CBC_NO_PADDING);
psa_set_key_usage_flags(&attr, usage);
psa_set_key_bits(&attr, 128);
psa_set_key_type(&attr, PSA_KEY_TYPE_AES);
#ifdef SECURE_ELEMENT
psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION
(PSA_KEY_LIFETIME_VOLATILE, PSA_ATCA_LOCATION_DEV0);
psa_set_key_lifetime(&attr, lifetime);
#endif
status = psa_import_key(&attr, KEY_128, AES_128_KEY_SIZE, &key_id);
if (status != PSA_SUCCESS) {
return status;
}
status = psa_cipher_encrypt(key_id, PSA_ALG_CBC_NO_PADDING, PLAINTEXT,
PLAINTEXT_LEN, cipher_out, encr_output_size, &output_len);
if (status != PSA_SUCCESS) {
return status;
}
status = psa_cipher_decrypt(key_id, PSA_ALG_CBC_NO_PADDING, cipher_out,
sizeof(cipher_out), plain_out, sizeof(plain_out), &output_len);
if (status == PSA_SUCCESS) {
return (memcmp(PLAINTEXT, plain_out, sizeof(plain_out)) ? -1 : 0);
}
return status;
}
#ifdef MULTIPLE_SE
psa_status_t example_cipher_aes_128_sec_se(void)
{
psa_status_t status = PSA_ERROR_DOES_NOT_EXIST;
psa_key_id_t key_id = 0;
psa_key_attributes_t attr = psa_key_attributes_init();
psa_key_usage_t usage = PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT;
psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(
PSA_KEY_LIFETIME_VOLATILE, PSA_ATCA_LOCATION_DEV1);
size_t encr_output_size = PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_AES,
PSA_ALG_CBC_NO_PADDING, PLAINTEXT_LEN);
uint8_t cipher_out[encr_output_size];
uint8_t plain_out[sizeof(PLAINTEXT)];
size_t output_len = 0;
psa_set_key_lifetime(&attr, lifetime);
psa_set_key_algorithm(&attr, PSA_ALG_CBC_NO_PADDING);
psa_set_key_usage_flags(&attr, usage);
psa_set_key_bits(&attr, 128);
psa_set_key_type(&attr, PSA_KEY_TYPE_AES);
status = psa_import_key(&attr, KEY_128, AES_128_KEY_SIZE, &key_id);
if (status != PSA_SUCCESS) {
return status;
}
status = psa_cipher_encrypt(key_id, PSA_ALG_CBC_NO_PADDING, PLAINTEXT,
PLAINTEXT_LEN, cipher_out, encr_output_size, &output_len);
if (status != PSA_SUCCESS) {
return status;
}
status = psa_cipher_decrypt(key_id, PSA_ALG_CBC_NO_PADDING, cipher_out,
sizeof(cipher_out), plain_out, sizeof(plain_out), &output_len);
if (status == PSA_SUCCESS) {
return (memcmp(PLAINTEXT, plain_out, sizeof(plain_out)) ? -1 : 0);
}
return status;
}
#endif

View File

@ -0,0 +1,177 @@
/*
* Copyright (C) 2022 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup examples
* @{
*
* @brief Example functions for ECDSA with PSA Crypto
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include <stdio.h>
#include <stdint.h>
#include "psa/crypto.h"
#define ECDSA_MESSAGE_SIZE (127)
#define ECC_KEY_SIZE (256)
/**
* @brief Example function to perform an ECDSA operation with a NIST P256 curve
* with the PSA Crypto API.
*
* @return psa_status_t
*/
psa_status_t example_ecdsa_p256(void)
{
psa_key_id_t privkey_id;
psa_key_attributes_t privkey_attr = psa_key_attributes_init();
psa_key_id_t pubkey_id;
psa_key_attributes_t pubkey_attr = psa_key_attributes_init();
psa_key_usage_t usage = PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH;
psa_key_type_t type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1);
psa_algorithm_t alg = PSA_ALG_ECDSA(PSA_ALG_SHA_256);
psa_key_bits_t bits = ECC_KEY_SIZE;
uint8_t bytes =
PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), bits);
uint8_t public_key[PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(PSA_KEY_TYPE_ECC_KEY_PAIR(
PSA_ECC_FAMILY_SECP_R1),
ECC_KEY_SIZE)] = { 0 };
size_t pubkey_length;
uint8_t signature[PSA_SIGN_OUTPUT_SIZE(type, bits, alg)];
size_t sig_length;
uint8_t msg[ECDSA_MESSAGE_SIZE] = { 0x0b };
uint8_t hash[PSA_HASH_LENGTH(PSA_ALG_SHA_256)];
size_t hash_length;
psa_set_key_algorithm(&privkey_attr, alg);
psa_set_key_usage_flags(&privkey_attr, usage);
psa_set_key_type(&privkey_attr, type);
psa_set_key_bits(&privkey_attr, bits);
#ifdef SECURE_ELEMENT
psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(
PSA_KEY_LIFETIME_VOLATILE, PSA_ATCA_LOCATION_DEV0);
psa_set_key_lifetime(&privkey_attr, lifetime);
#endif
psa_status_t status = PSA_ERROR_DOES_NOT_EXIST;
status = psa_generate_key(&privkey_attr, &privkey_id);
if (status != PSA_SUCCESS) {
return status;
}
status = psa_export_public_key(privkey_id, public_key, sizeof(public_key), &pubkey_length);
if (status != PSA_SUCCESS) {
return status;
}
status = psa_hash_compute(PSA_ALG_SHA_256, msg, sizeof(msg), hash, sizeof(hash), &hash_length);
if (status != PSA_SUCCESS) {
return status;
}
#ifdef SECURE_ELEMENT
psa_set_key_lifetime(&pubkey_attr, lifetime);
#endif
psa_set_key_algorithm(&pubkey_attr, alg);
psa_set_key_usage_flags(&pubkey_attr, PSA_KEY_USAGE_VERIFY_HASH);
psa_set_key_bits(&pubkey_attr, PSA_BYTES_TO_BITS(bytes));
psa_set_key_type(&pubkey_attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
status = psa_import_key(&pubkey_attr, public_key, pubkey_length, &pubkey_id);
if (status != PSA_SUCCESS) {
return status;
}
status = psa_sign_hash(privkey_id, alg, hash, sizeof(hash), signature, sizeof(signature),
&sig_length);
if (status != PSA_SUCCESS) {
return status;
}
return psa_verify_hash(pubkey_id, alg, hash, sizeof(hash), signature, sig_length);
}
#ifdef MULTIPLE_SE
psa_status_t example_ecdsa_p256_sec_se(void)
{
psa_key_id_t privkey_id;
psa_key_attributes_t privkey_attr = psa_key_attributes_init();
psa_key_id_t pubkey_id;
psa_key_attributes_t pubkey_attr = psa_key_attributes_init();
psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(
PSA_KEY_LIFETIME_VOLATILE, PSA_ATCA_LOCATION_DEV1);
psa_key_usage_t usage = PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH;
psa_key_type_t type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1);
psa_algorithm_t alg = PSA_ALG_ECDSA(PSA_ALG_SHA_256);
psa_key_bits_t bits = 256;
uint8_t bytes =
PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), bits);
uint8_t public_key[PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(PSA_KEY_TYPE_ECC_KEY_PAIR(
PSA_ECC_FAMILY_SECP_R1), 256)] = { 0 };
size_t pubkey_length;
uint8_t signature[PSA_SIGN_OUTPUT_SIZE(type, bits, alg)];
size_t sig_length;
uint8_t msg[ECDSA_MESSAGE_SIZE] = { 0x0b };
uint8_t hash[PSA_HASH_LENGTH(PSA_ALG_SHA_256)];
size_t hash_length;
psa_set_key_lifetime(&privkey_attr, lifetime);
psa_set_key_algorithm(&privkey_attr, alg);
psa_set_key_usage_flags(&privkey_attr, usage);
psa_set_key_type(&privkey_attr, type);
psa_set_key_bits(&privkey_attr, bits);
psa_status_t status = PSA_ERROR_DOES_NOT_EXIST;
status = psa_generate_key(&privkey_attr, &privkey_id);
if (status != PSA_SUCCESS) {
return status;
}
status = psa_export_public_key(privkey_id, public_key, sizeof(public_key), &pubkey_length);
if (status != PSA_SUCCESS) {
return status;
}
status = psa_hash_compute(PSA_ALG_SHA_256, msg, sizeof(msg), hash, sizeof(hash), &hash_length);
if (status != PSA_SUCCESS) {
return status;
}
psa_set_key_lifetime(&pubkey_attr, lifetime);
psa_set_key_algorithm(&pubkey_attr, alg);
psa_set_key_usage_flags(&pubkey_attr, PSA_KEY_USAGE_VERIFY_HASH);
psa_set_key_bits(&pubkey_attr, PSA_BYTES_TO_BITS(bytes));
psa_set_key_type(&pubkey_attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
status = psa_import_key(&pubkey_attr, public_key, pubkey_length, &pubkey_id);
if (status != PSA_SUCCESS) {
return status;
}
status = psa_sign_hash(privkey_id, alg, hash, sizeof(hash), signature, sizeof(signature),
&sig_length);
if (status != PSA_SUCCESS) {
return status;
}
return psa_verify_hash(pubkey_id, alg, hash, sizeof(hash), signature, sig_length);
}
#endif

View File

@ -0,0 +1,111 @@
/*
* Copyright (C) 2022 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup examples
* @{
*
* @brief Example functions for HMAC SHA256 with PSA Crypto
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include <stdio.h>
#include <stdint.h>
#include "psa/crypto.h"
static const uint8_t HMAC_KEY[] = {
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b
};
static size_t HMAC_KEY_LEN = 32;
static const uint8_t HMAC_MSG[] = {
0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x73, 0x74,
0x72, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x6f, 0x72,
0x20, 0x68, 0x6d, 0x61, 0x63, 0x32, 0x35, 0x36
};
static size_t HMAC_MSG_LEN = 32;
/**
* @brief Example function to perform an HMAC SHA-256 computation
* with the PSA Crypto API.
*
* @return psa_status_t
*/
psa_status_t example_hmac_sha256(void)
{
psa_key_attributes_t attr = psa_key_attributes_init();
psa_key_id_t key_id = 0;
psa_key_usage_t usage = PSA_KEY_USAGE_SIGN_MESSAGE;
size_t digest_size =
PSA_MAC_LENGTH(PSA_KEY_TYPE_HMAC, HMAC_KEY_LEN, PSA_ALG_HMAC(PSA_ALG_SHA_256));
uint8_t digest[digest_size];
size_t output_len = 0;
psa_set_key_algorithm(&attr, PSA_ALG_HMAC(PSA_ALG_SHA_256));
psa_set_key_usage_flags(&attr, usage);
psa_set_key_bits(&attr, PSA_BYTES_TO_BITS(HMAC_KEY_LEN));
psa_set_key_type(&attr, PSA_KEY_TYPE_HMAC);
#ifdef SECURE_ELEMENT
psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(
PSA_KEY_LIFETIME_VOLATILE, PSA_ATCA_LOCATION_DEV0);
psa_set_key_lifetime(&attr, lifetime);
#endif
psa_status_t status = PSA_ERROR_DOES_NOT_EXIST;
status = psa_import_key(&attr, HMAC_KEY, HMAC_KEY_LEN, &key_id);
if (status != PSA_SUCCESS) {
return status;
}
return psa_mac_compute(key_id, PSA_ALG_HMAC(PSA_ALG_SHA_256),
HMAC_MSG, HMAC_MSG_LEN, digest, digest_size,
&output_len);
}
#if MULTIPLE_SE
psa_status_t example_hmac_sha256_sec_se(void)
{
psa_key_attributes_t attr = psa_key_attributes_init();
psa_key_id_t key_id = 0;
psa_key_usage_t usage = PSA_KEY_USAGE_SIGN_MESSAGE;
psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(
PSA_KEY_LIFETIME_VOLATILE, PSA_ATCA_LOCATION_DEV1);
size_t digest_size =
PSA_MAC_LENGTH(PSA_KEY_TYPE_HMAC, HMAC_KEY_LEN, PSA_ALG_HMAC(PSA_ALG_SHA_256));
uint8_t digest[digest_size];
size_t output_len = 0;
psa_set_key_lifetime(&attr, lifetime);
psa_set_key_algorithm(&attr, PSA_ALG_HMAC(PSA_ALG_SHA_256));
psa_set_key_usage_flags(&attr, usage);
psa_set_key_bits(&attr, PSA_BYTES_TO_BITS(HMAC_KEY_LEN));
psa_set_key_type(&attr, PSA_KEY_TYPE_HMAC);
psa_status_t status = PSA_ERROR_DOES_NOT_EXIST;
status = psa_import_key(&attr, HMAC_KEY, HMAC_KEY_LEN, &key_id);
if (status != PSA_SUCCESS) {
return status;
}
return psa_mac_compute(key_id, PSA_ALG_HMAC(PSA_ALG_SHA_256),
HMAC_MSG, HMAC_MSG_LEN, digest, digest_size,
&output_len);
}
#endif

View File

@ -0,0 +1,90 @@
/*
* Copyright (C) 2022 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup examples
* @{
*
* @brief Example application for PSA Crypto
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include <stdio.h>
#include "psa/crypto.h"
#include "ztimer.h"
extern psa_status_t example_cipher_aes_128(void);
extern psa_status_t example_hmac_sha256(void);
extern psa_status_t example_ecdsa_p256(void);
#ifdef MULTIPLE_SE
extern psa_status_t example_cipher_aes_128_sec_se(void);
extern psa_status_t example_hmac_sha256_sec_se(void);
extern psa_status_t example_ecdsa_p256_sec_se(void);
#endif
int main(void)
{
psa_status_t status;
psa_crypto_init();
ztimer_acquire(ZTIMER_USEC);
ztimer_now_t start = ztimer_now(ZTIMER_USEC);
status = example_hmac_sha256();
printf("HMAC SHA256 took %d us\n", (int)(ztimer_now(ZTIMER_USEC) - start));
if (status != PSA_SUCCESS) {
printf("HMAC SHA256 failed: %s\n", psa_status_to_humanly_readable(status));
}
start = ztimer_now(ZTIMER_USEC);
status = example_cipher_aes_128();
printf("Cipher AES 128 took %d us\n", (int)(ztimer_now(ZTIMER_USEC) - start));
if (status != PSA_SUCCESS) {
printf("Cipher AES 128 failed: %s\n", psa_status_to_humanly_readable(status));
}
start = ztimer_now(ZTIMER_USEC);
status = example_ecdsa_p256();
printf("ECDSA took %d us\n", (int)(ztimer_now(ZTIMER_USEC) - start));
if (status != PSA_SUCCESS) {
printf("ECDSA failed: %s\n", psa_status_to_humanly_readable(status));
}
#ifdef MULTIPLE_SE
puts("Running Examples with secondary SE:");
status = example_hmac_sha256_sec_se();
printf("HMAC SHA256 took %d us\n", (int)(ztimer_now(ZTIMER_USEC) - start));
if (status != PSA_SUCCESS) {
printf("HMAC SHA256 failed: %s\n", psa_status_to_humanly_readable(status));
}
start = ztimer_now(ZTIMER_USEC);
status = example_cipher_aes_128_sec_se();
printf("Cipher AES 128 took %d us\n", (int)(ztimer_now(ZTIMER_USEC) - start));
if (status != PSA_SUCCESS) {
printf("Cipher AES 128 failed: %s\n", psa_status_to_humanly_readable(status));
}
start = ztimer_now(ZTIMER_USEC);
status = example_ecdsa_p256_sec_se();
printf("ECDSA took %d us\n", (int)(ztimer_now(ZTIMER_USEC) - start));
if (status != PSA_SUCCESS) {
printf("ECDSA failed: %s\n", psa_status_to_humanly_readable(status));
}
#endif
ztimer_release(ZTIMER_USEC);
puts("All Done");
return 0;
}

View File

@ -0,0 +1,13 @@
#!/usr/bin/env python3
import sys
from testrunner import run
def testfunc(child):
child.expect_exact('All Done')
print("[TEST PASSED]")
if __name__ == "__main__":
sys.exit(run(testfunc))

View File

@ -134,6 +134,11 @@ config HAS_CPU_CHECK_ADDRESS
help
Indicates that address validity check is supported.
config HAS_PERIPH_CRYPTOCELL_310
bool
help
Indicates that a cryptocell peripheral is present.
config HAS_DBGPIN
bool
help
@ -188,6 +193,11 @@ config HAS_PERIPH_CAN
help
Indicates that a CAN peripheral is present.
config HAS_PERIPH_CIPHER_AES_128_CBC
bool
help
Indicates that there is AES 128 CBC hardware acceleration present
config HAS_PERIPH_CORETIMER
bool
help
@ -208,6 +218,16 @@ config HAS_PERIPH_DMA
help
Indicates that a DMA peripheral is present.
config HAS_PERIPH_ECC_P192R1
bool
help
Indicates that there is ECC P192R1 hardware acceleration peripheral present.
config HAS_PERIPH_ECC_P256R1
bool
help
Indicates that there is ECC P256R1 hardware acceleration peripheral present.
config HAS_PERIPH_EEPROM
bool
help
@ -285,6 +305,36 @@ config HAS_PERIPH_GPIO_LL_IRQ_UNMASK
Indicates that the GPIO peripheral supports unmasking interrupts without
clearing pending IRQs that came in while masked.
config HAS_PERIPH_HASH_MD5
bool
help
Indicates that there is MD5 hardware acceleration present.
config HAS_PERIPH_HASH_SHA_1
bool
help
Indicates that there is SHA-1 hardware acceleration present.
config HAS_PERIPH_HASH_SHA_224
bool
help
Indicates that there is SHA-224 hardware acceleration present.
config HAS_PERIPH_HASH_SHA_256
bool
help
Indicates that there is SHA-256 hardware acceleration present.
config HAS_PERIPH_HASH_SHA_512
bool
help
Indicates that there is SHA-512 hardware acceleration present.
config HAS_PERIPH_HMAC_SHA_256
bool
help
Indicates that there is HMAC SHA-256 hardware acceleration present.
config HAS_PERIPH_HWRNG
bool
help

View File

@ -93,4 +93,12 @@ else
"don't run this on public networks!$(COLOR_RESET)" 1>&2)
endif
endif
# Warn about PSA Crypto
ifneq (,$(filter psa_crypto,$(USEMODULE)))
$(shell $(COLOR_ECHO) "$(COLOR_YELLOW) You are going to use the PSA Crypto module,"\
"which is only partly implemented and not yet thouroughly tested.\n"\
"Please do not use this module in production, as it may introduce"\
"security issues!$(COLOR_RESET)" 1>&2)
endif
endif

View File

@ -11,9 +11,13 @@ USEMODULE += $(PERIPH_FEATURES)
# Add all USED periph_% init modules unless they are blacklisted
PERIPH_IGNORE_MODULES := \
periph_cipher_aes_128_cbc \
periph_clic \
periph_common \
periph_coretimer \
periph_cryptocell_310 \
periph_ecc_p192r1 \
periph_ecc_p256r1 \
periph_eth \
periph_eth_common \
periph_flash \
@ -25,6 +29,11 @@ PERIPH_IGNORE_MODULES := \
periph_gpio_ll_irq_level_triggered_low \
periph_gpio_ll_irq_unmask \
periph_gpio_mux \
periph_hash_sha_1 \
periph_hash_sha_224 \
periph_hash_sha_256 \
periph_hash_sha_512 \
periph_hmac_sha_256 \
periph_i2c_hw \
periph_i2c_sw \
periph_init% \

View File

@ -388,6 +388,16 @@ PSEUDOMODULES += posix_headers
PSEUDOMODULES += printf_float
PSEUDOMODULES += prng
PSEUDOMODULES += prng_%
PSEUDOMODULES += psa_riot_cipher_aes_common
PSEUDOMODULES += psa_riot_cipher_aes_128_ecb
PSEUDOMODULES += psa_riot_cipher_aes_128_cbc
PSEUDOMODULES += psa_riot_cipher_aes_192_cbc
PSEUDOMODULES += psa_riot_cipher_aes_256_cbc
PSEUDOMODULES += psa_riot_hashes_md5
PSEUDOMODULES += psa_riot_hashes_sha_1
PSEUDOMODULES += psa_riot_hashes_sha_224
PSEUDOMODULES += psa_riot_hashes_sha_256
PSEUDOMODULES += psa_riot_hashes_hmac_sha256
PSEUDOMODULES += fortuna_reseed
## @defgroup pseudomodule_random_cmd random_cmd
## @ingroup sys_shell_commands

View File

@ -17,6 +17,7 @@ rsource "corejson/Kconfig"
rsource "cryptoauthlib/Kconfig"
rsource "driver_atwinc15x0/Kconfig"
rsource "driver_bme680/Kconfig"
rsource "driver_cryptocell_310/Kconfig"
rsource "driver_sx126x/Kconfig"
rsource "elk/Kconfig"
rsource "emlearn/Kconfig"

View File

@ -9,6 +9,7 @@ menuconfig PACKAGE_CRYPTOAUTHLIB
bool "Microchip CryptoAuthentication Library package"
depends on TEST_KCONFIG
depends on !HAS_ARCH_EFM32
depends on HAS_PERIPH_I2C
select MODULE_AUTO_INIT_SECURITY
select MODULE_CRYPTOAUTHLIB_CONTRIB
@ -20,6 +21,12 @@ config MODULE_CRYPTOAUTHLIB_CONTRIB
select MODULE_PERIPH_I2C
select MODULE_PERIPH_I2C_RECONFIGURE if HAS_PERIPH_I2C_RECONFIGURE
config MODULE_PSA_ATCA_DRIVER
bool
depends on PACKAGE_CRYPTOAUTHLIB
default y if MODULE_PSA_CRYPTO
select PSA_KEY_MANAGEMENT
config MODULE_CRYPTOAUTHLIB_TEST
bool "Module for cryptoauthlib tests"
depends on TEST_KCONFIG
@ -56,4 +63,4 @@ config MODULE_CRYPTOAUTHLIB_TEST_API_CRYPTO
config MODULE_CRYPTOAUTHLIB_TEST_VECTORS
bool
endif
endif # PACKAGE_CRYPTOAUTHLIB

View File

@ -10,7 +10,7 @@ include $(RIOTBASE)/pkg/pkg.mk
CMAKE_MINIMAL_VERSION = 3.6.0
CFLAGS += $(INCLUDES)
CFLAGS += $(INCLUDES) # for some reason this is needed by llvm, but not for gcc
CFLAGS += -DATCA_HAL_I2C
CFLAGS += -Wno-cast-align
CFLAGS += -Wno-char-subscripts

View File

@ -19,3 +19,11 @@ endif
# Some EFM32 CPU families define AES_COUNT, which is also defined by this
# library.
FEATURES_BLACKLIST += arch_efm32
ifneq (,$(filter psa_crypto,$(USEMODULE)))
USEMODULE += psa_atca_driver
endif
ifneq (,$(filter psa_secure_element_ateccx08a_ecc_p256, $(USEMODULE)))
USEMODULE += psa_secure_element_asymmetric
endif

View File

@ -7,6 +7,11 @@ INCLUDES += -I$(PKG_SOURCE_DIR)/app
INCLUDES += -I$(PKG_SOURCE_DIR)/lib/calib
INCLUDES += -I$(RIOTPKG)/cryptoauthlib/include
ifneq (,$(filter psa_crypto, $(USEMODULE)))
DIRS += $(RIOTPKG)/cryptoauthlib/psa_atca_driver
INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include
endif
DIRS += $(RIOTPKG)/cryptoauthlib/contrib
ARCHIVES += $(BINDIR)/cryptoauthlib.a
@ -21,3 +26,8 @@ ifneq (,$(filter cryptoauthlib_test,$(USEMODULE)))
INCLUDES += -I$(PKG_TESTINCLDIR)/vectors
INCLUDES += -I$(PKG_SOURCE_DIR)/third_party/unity
endif
ifneq (,$(filter psa_crypto,$(USEMODULE)))
PSEUDOMODULES += psa_secure_element_ateccx08a
PSEUDOMODULES += psa_secure_element_ateccx08a_ecc_p256
endif

View File

@ -27,7 +27,6 @@
#include "atca.h"
#include "atca_params.h"
/* Timer functions */
void atca_delay_us(uint32_t delay)
{
@ -65,7 +64,7 @@ ATCA_STATUS hal_i2c_post_init(ATCAIface iface)
ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t word_address, uint8_t *txdata, int txlength)
{
(void) word_address;
(void)word_address;
ATCAIfaceCfg *cfg = atgetifacecfg(iface);
int ret;
@ -84,7 +83,7 @@ ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t word_address, uint8_t *txdata,
ATCA_STATUS hal_i2c_receive(ATCAIface iface, uint8_t word_address, uint8_t *rxdata,
uint16_t *rxlength)
{
(void) word_address;
(void)word_address;
ATCAIfaceCfg *cfg = atgetifacecfg(iface);
uint8_t retries = cfg->rx_retries;
int ret = -1;
@ -170,24 +169,24 @@ ATCA_STATUS hal_i2c_sleep(ATCAIface iface)
return ATCA_SUCCESS;
}
ATCA_STATUS hal_i2c_control(ATCAIface iface, uint8_t option, void* param, size_t paramlen)
ATCA_STATUS hal_i2c_control(ATCAIface iface, uint8_t option, void *param, size_t paramlen)
{
(void) param;
(void) paramlen;
(void)param;
(void)paramlen;
switch (option) {
case ATCA_HAL_CONTROL_WAKE:
return hal_i2c_wake(iface);
case ATCA_HAL_CONTROL_IDLE:
return hal_i2c_idle(iface);
case ATCA_HAL_CONTROL_SLEEP:
return hal_i2c_sleep(iface);
case ATCA_HAL_CHANGE_BAUD:
return ATCA_UNIMPLEMENTED;
case ATCA_HAL_CONTROL_SELECT:
case ATCA_HAL_CONTROL_DESELECT:
return ATCA_SUCCESS;
default:
return ATCA_BAD_PARAM;
case ATCA_HAL_CONTROL_WAKE:
return hal_i2c_wake(iface);
case ATCA_HAL_CONTROL_IDLE:
return hal_i2c_idle(iface);
case ATCA_HAL_CONTROL_SLEEP:
return hal_i2c_sleep(iface);
case ATCA_HAL_CHANGE_BAUD:
return ATCA_UNIMPLEMENTED;
case ATCA_HAL_CONTROL_SELECT:
case ATCA_HAL_CONTROL_DESELECT:
return ATCA_SUCCESS;
default:
return ATCA_BAD_PARAM;
}
return ATCA_UNIMPLEMENTED;
}

View File

@ -1,6 +1,6 @@
/**
* @defgroup pkg_cryptoauthlib Microchip CryptoAuthentication Library
* @ingroup pkg drivers_misc sys_crypto
* @ingroup pkg drivers_misc
* @brief Provides the library for Microchip CryptoAuth devices
* @see https://github.com/MicrochipTech/cryptoauthlib
*
@ -8,22 +8,19 @@
*
* This package provides support for the official library for Microchip CryptoAuth devices.
*
*
* ## Warning
*
* Some functions can only be used, when the data, config and otp zones of the
* device are locked. Locking is permanent and cannot be undone. Be careful if
* you're not sure you've configured everything correctly.
* For more information we refer to the data sheet of the device.
*
* @warning Some functions can only be used, when the data, config and otp zones
* of the device are locked. Locking is permanent and cannot be undone.
* Be careful if you're not sure you've configured everything correctly.
* For more information please refer to the data sheet of the device.
*
* ## Usage
*
* Add
* @code
* USEPKG += cryptoauthlib
* @endcode
* to your Makefile.
*
*
* ### Shell
*
* To facilitate the device configuration the RIOT shell provides some
@ -33,7 +30,6 @@
* The shell handler is enabled, if cryptoauthlib is included as a package in the
* Makefile of an application that also includes the shell (e.g. examples/default).
*
*
* ### No poll mode
*
* After sending a command to the device, responses are usually polled to enable
@ -41,25 +37,11 @@
* Alternatively ATCA_NO_POLL can be enabled through CFLAGS to simply
* wait for the max execution time of a command before reading the response.
*
*
* ## Implementation status
*
* This implementation was partly tested with ATECC508A and ATECC608A devices.
* We haven't tested the functions that require locking the device, yet. There's
* a wrapper in the cryptoauthlib/contrib folder, which implements most of the
* HAL functions.
* Currently the functions hal_i2c_discover_devices and hal_i2c_discover_buses
* are unimplemented, as well as hal_i2c_post_init.
*
* ### Wake function
*
* The wake function only works when a 0x00 byte is sent on an i2c interface that
* runs with with 133kHz or less.
* Currently RIOT sets the baudrate to the default value of 100 kHz and there's
* no interface to change that. If the default speed ever changes to a value
* higher than 133 kHz the wake function needs to be adapted.
* For more information on how to send a proper wake condition we refer to the
* data sheet of the device.
* Currently the functions `hal_i2c_release`, `hal_i2c_discover_devices` and
* `hal_i2c_discover_buses` are unimplemented, as well as `hal_i2c_post_init`.
*
* ## Tests
*
@ -72,4 +54,189 @@
* permanently. Unlocking is not possible!
* Also there is a test for comparing the runtime of the RIOT software implementation
* and the CryptoAuth hardware implementation for calculating a SHA-256 hash value.
*
* ## Using Multiple ATECCX08A Devices {#multi-ateccx08a}
*
* When using more than one device, you can either connect devices with different
* I2C addresses to one bus or devices with the same address to separate buses.
* The ATECCX08A devices provide a way to change the I2C address during device
* configuration (for more details, read the datasheet or the API documentation).
*
* ATECCX08A device parameters are configured in
* `RIOT/pkg/cryptoauthlib/include/atca_params.h`.
* There you can specify your device's address, the I2C bus to use and more by
* defining `ATCA_PARAMS`. Per default one device is defined in RIOT (example shown below).
*
* @code
* #define ATCA_PARAM_I2C (I2C_DEV(0))
* #define ATCA_PARAM_ADDR (ATCA_I2C_ADDR)
* #define ATCA_RX_RETRIES (20)
* #define ATCA_DEVTYPE (ATECC608A)
*
* #define ATCA_PARAMS { .iface_type = ATCA_I2C_IFACE, \
* .devtype = ATCA_DEVTYPE, \
* .atcai2c.address = ATCA_PARAM_ADDR, \
* .atcai2c.bus = ATCA_PARAM_I2C, \
* .atcai2c.baud = -1, \
* .wake_delay = 1500, \
* .rx_retries = ATCA_RX_RETRIES }
* @endcode
*
* If you want to use more than one device, the best way is to create a file called
* `custom_atca_params.h` in your application folder (you can see an example of this in
* `examples/psa_crypto`).
*
* In your custom file you can now add a second device to `ATCA_PARAMS`:
* @code
* #define ATCA_PARAM_I2C_DEV0 (I2C_DEV(0))
* #define ATCA_PARAM_ADDR_DEV0 (ATCA_I2C_ADDR_DEV0)
* #define ATCA_RX_RETRIES_DEV0 (20)
* #define ATCA_DEVTYPE_DEV0 (ATECC608A)
*
* #define ATCA_PARAM_I2C_DEV1 (I2C_DEV(0))
* #define ATCA_PARAM_ADDR_DEV1 (ATCA_I2C_ADDR_DEV1)
* #define ATCA_RX_RETRIES_DEV1 (20)
* #define ATCA_DEVTYPE_DEV1 (ATECC608A)
*
* #define ATCA_PARAMS { .iface_type = ATCA_I2C_IFACE, \
* .devtype = ATCA_DEVTYPE_DEV0, \
* .atcai2c.address = ATCA_PARAM_ADDR_DEV0, \
* .atcai2c.bus = ATCA_PARAM_I2C_DEV0, \
* .atcai2c.baud = -1, \
* .wake_delay = 1500, \
* .rx_retries = ATCA_RX_RETRIES }, \
* { .iface_type = ATCA_I2C_IFACE, \
* .devtype = ATCA_DEVTYPE_DEV1, \
* .atcai2c.address = ATCA_PARAM_ADDR_DEV1, \
* .atcai2c.bus = ATCA_PARAM_I2C_DEV1, \
* .atcai2c.baud = -1, \
* .wake_delay = 1500, \
* .rx_retries = ATCA_RX_RETRIES }
* @endcode
*
* Now you just need to add the following to your Makefile:
* @code
* CFLAGS += -DCUSTOM_ATCA_PARAMS
* INCLUDES += -I$(APPDIR)
* @endcode
*
* This way your custom params file is included in the build process and both your
* devices will be initialized by the `auto_init` module.
*
* To use them you need to utilize the `calib`-API of the cryptoauth driver, which
* allows you to pass a device handle. Pointers to all initialized devices are stored
* in the `atca_devs_ptr` array, which is included in `atca_params.h`.
* Include `atca_params.h` in your source file and pass the device handle as shown below.
*
* @code {.c}
* ATCADevice dev = atca_devs_ptr[0];
* calib_sha_start(dev);
* @endcode
*
* ## Using Cryptoauthlib as a backend for PSA Crypto {#psa-cryptoauthlib}
*
* To use cryptoauthlib as a backend for [PSA Crypto](#sys_psa_crypto), it is best to
* overwrite the `atca_params.h` file with your own `custom_atca_params.h` file, similar
* to the one described in [Using Multiple ATECCX08A Devices](#multi-ateccx08a).
*
* When using PSA, the `ATCA_PARAMS` define contains an additional value: A location
* value of the type @ref psa_key_location_t. Each secure element you use needs its own
* location value. The primary device can get the value
* @ref PSA_KEY_LOCATION_PRIMARY_SECURE_ELEMENT. All others must be within the range of
* @ref PSA_KEY_LOCATION_SE_MIN and @ref PSA_KEY_LOCATION_SE_MAX.
*
* Your structure should now look like this:
* @code
* #define PSA_ATCA_LOCATION (PSA_KEY_LOCATION_PRIMARY_SECURE_ELEMENT)
* #define ATCA_PARAM_I2C (I2C_DEV(0))
* #define ATCA_PARAM_ADDR (ATCA_I2C_ADDR)
* #define ATCA_DEVTYPE (ATECC608A)
* #define ATCA_RX_RETRIES (20)
*
* #define ATCA_PARAMS { .atca_loc = PSA_ATCA_LOCATION,\
* .cfg = {\
* .iface_type = ATCA_I2C_IFACE, \
* .devtype = ATCA_DEVTYPE, \
* .atcai2c.address = ATCA_PARAM_ADDR, \
* .atcai2c.bus = ATCA_PARAM_I2C, \
* .atcai2c.baud = -1, \
* .wake_delay = 1500, \
* .rx_retries = ATCA_RX_RETRIES } \
* }
* @endcode
*
* When using multiple SEs, just add more device parameters as shown in section
* [Using Multiple ATECCX08A Devices](#multi-ateccx08a).
*
* ## Slot Configurations
* The ATECCX08A devices have their own key management, which can be configured by
* setting flags in the device's configuration and data zone. There is a large variety
* of possible configurations, which can not entirely be represented by PSA Crypto.
*
* For now we assume that users are familiar with their device's datasheet and have configured
* it in a way that it is usable. PSA can not yet work with keys that are already stored on the
* device, which means all key slots must be writable after locking the configuration and data zone.
*
* For ECC operations this means that key slot configurations need to allow at least the
* use of the `gen_key` command, for AES and HMAC key slots it means that clear write operations
* must be allowed.
*
* @warning In case of AES and HMAC keys this may lead to security issues,
* as it allows for manipulating key material.
*
* Users need to make their configurations known to PSA Crypto.
* For this you need to initialize a list of key slot configuration structures, with a structure
* for each slot.
*
* For these devices the structure looks like this:
* @code {.c}
* typedef struct {
* psa_key_type_t key_type_allowed; // Declare the key type allowed in this slot
* uint8_t key_persistent; // Ignore for now, PSA does not yet support persistent keys
* uint8_t slot_occupied; // Set to 0, PSA will set this to one after writing a key
* } psa_atca_slot_config_t;
* @endcode
*
* To make your configurations known to PSA, simply add the following to your `custom_atca_params.h`
* file (these values are only an example, of course you need to modify them according to
* your needs).
*
* @code {.c}
* #define ATCA_SLOTS_DEV0 { { PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
* { PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
* { PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
* { PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
* { PSA_KEY_TYPE_AES, 0, 0 }, \
* { PSA_KEY_TYPE_HMAC, 0, 0 }, \
* { PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
* { 0, 1, 1 }, \
* { 0, 0, 0 }, \
* { PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
* { PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
* { PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
* { PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
* { PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1), 0, 0 }, \
* { 0, 0, 0 }, \
* { 0, 0, 0 }}
*
* #define ATCA_CONFIG_LIST { ATCA_SLOTS_DEV0 }
* @endcode
*
* To use multiple devices, define `ATCA_SLOTS_DEV0` - `ATCA_SLOTS_DEVX` and add them to
* `ATCA_CONFIG_LIST` like so:
*
* @code {.c}
* #define ATCA_CONFIG_LIST { ATCA_SLOTS_DEV0 }, \
* { ATCA_SLOTS_DEV1 }, \
* ... \
* { ATCA_SLOTS_DEVX }
* @endcode
*
* A usage example for this can be found in `examples/psa_crypto`.
*
* ## Troubleshooting
*
* ### Device Initialization fails
*
* Make sure the I2C bus speed is set to `I2C_SPEED_NORMAL`.
*/

View File

@ -29,6 +29,7 @@ extern "C" {
/**
* @brief Default device and word addresses for ATECC508A
* @{
*/
#define ATCA_I2C_ADDR (0xC0) /**< Default device address is 0xC0 */
@ -36,6 +37,38 @@ extern "C" {
#define ATCA_SLEEP_ADDR (0x01) /**< Word address to write to for sleep mode */
#define ATCA_IDLE_ADDR (0x02) /**< Word address to write to for idle mode */
#define ATCA_DATA_ADDR (0x03) /**< Word address to read and write to data area */
/** @} */
#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A)
#include "psa/crypto_types.h"
/**
* @brief Structure containing the Cryptoauthlib specific AES context
*/
typedef struct {
uint8_t iv[16];
psa_encrypt_or_decrypt_t direction;
union atca_context {
atca_aes_cbc_ctx_t aes_cbc;
} aes_ctx;
} psa_atca_cipher_context_t;
/**
* @brief Structure containing information about which type of key
* can be held by a specific key slot on an ATECCX08 device.
*
* If a slot should be ignored by the implementation,
* just mark it as persistent and occupied.
*/
typedef struct {
/* Type of key permitted for slot */
psa_key_type_t key_type_allowed;
/* Specify if key should be stored persistently or can be overwritten */
uint8_t key_persistent;
/* Specify whether slot is already occupied */
uint8_t slot_occupied;
} psa_atca_slot_config_t;
#endif /* MODULE_PSA_SECURE_ELEMENT_ATECCX08A */
#ifdef __cplusplus
}

View File

@ -49,4 +49,4 @@ extern "C" {
}
#endif
#endif /* ATCA_CONFIG_H */
/** @} */
/** @} */

View File

@ -22,8 +22,19 @@
#include "board.h"
#include "periph/i2c.h"
#include "atca.h"
#include "cryptoauthlib.h"
#include "kernel_defines.h"
#ifdef CUSTOM_ATCA_PARAMS
#include "custom_atca_params.h"
#endif
#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A)
#include "psa/crypto_types.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
@ -45,8 +56,9 @@ extern "C" {
*/
#ifndef ATCA_PARAM_I2C
#define ATCA_PARAM_I2C I2C_DEV(0)
#define ATCA_PARAM_I2C (I2C_DEV(0))
#endif
#ifndef ATCA_PARAM_ADDR
#define ATCA_PARAM_ADDR (ATCA_I2C_ADDR)
#endif
@ -58,17 +70,37 @@ extern "C" {
#endif
#ifndef ATCA_PARAMS
#define ATCA_PARAMS { .iface_type = ATCA_I2C_IFACE, \
.devtype = ATCA_DEVTYPE, \
.atcai2c.address = ATCA_PARAM_ADDR, \
.atcai2c.bus = ATCA_PARAM_I2C, \
.atcai2c.baud = -1, /**< Not used in RIOT */ \
.wake_delay = 1500, \
.rx_retries = ATCA_RX_RETRIES }
/**
* @brief Configuration parameters for the primary ATCA device
*/
#define ATCA_PARAMS { .iface_type = ATCA_I2C_IFACE, \
.devtype = ATCA_DEVTYPE, \
.atcai2c.address = ATCA_PARAM_ADDR, \
.atcai2c.bus = ATCA_PARAM_I2C, \
.atcai2c.baud = -1, /**< Not used in RIOT */ \
.wake_delay = 1500, \
.rx_retries = ATCA_RX_RETRIES }
#endif
/**@}*/
#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A)
/**
* @brief Structure to store ATCA device configuration
*/
typedef struct {
psa_key_location_t atca_loc;
ATCAIfaceCfg cfg; /**< ATCA configuration parameters */
} atca_params_t;
/**
* @brief Allocation of ATCA device descriptors
*/
static const atca_params_t atca_params[] =
{
ATCA_PARAMS
};
#else
/**
* @brief Allocation of ATCA device descriptors
*/
@ -76,6 +108,17 @@ static const ATCAIfaceCfg atca_params[] =
{
ATCA_PARAMS
};
#endif
/**
* @brief Number of connected devices
*/
#define ATCA_NUMOF (ARRAY_SIZE(atca_params))
/**
* @brief List of device pointers for all available devices
*/
extern ATCADevice atca_devs_ptr[ATCA_NUMOF];
#ifdef __cplusplus
}

View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,691 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @{
*
* @file
* @brief Glue code translating between PSA Crypto and the Microchip Cryptoauth Library APIs
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include "atca_params.h"
#include "psa/crypto.h"
#include "psa_crypto_se_driver.h"
#define ENABLE_DEBUG 0
#include "debug.h"
/**
* @brief AES block size supported by ATCA devices
*/
#define AES_128_BLOCK_SIZE (16)
/**
* @brief AES key size supported by ATCA devices
*/
#define AES_128_KEY_SIZE (16)
/**
* @brief Size of an ellipic curve public key supported by ATCA devices
*/
#define ECC_P256_PUB_KEY_SIZE (64)
/**
* @brief Maximum IV length supported by ATCA devices
*/
#define ATCA_MAX_IV_LEN (16)
/**
* @brief Size of ATCA TempKey Register
*/
#define ATCA_WRITE_BUFFER_SIZE (32)
/**
* @brief Check whether a specified algorithm is supported by this driver
*
* @param alg Algorithm of type @ref psa_algorithm_t
*
* @return int
* 1 if @c alg is supported
* 0 otherwise
*/
#define ALG_IS_SUPPORTED(alg) \
((alg == PSA_ALG_ECB_NO_PADDING) || \
(alg == PSA_ALG_CBC_NO_PADDING) || \
(alg == PSA_ALG_ECDSA(PSA_ALG_SHA_256)) || \
(alg == PSA_ALG_HMAC(PSA_ALG_SHA_256)))
/**
* @brief Check whether a specified key size is supported by this driver
*
* @param size Size of the specified key
* @param type Type of the specified key
*
* @return int
* 1 if @c size is supported
* 0 otherwise
*/
#define KEY_SIZE_IS_SUPPORTED(size, type) \
((type == PSA_KEY_TYPE_AES && size == AES_128_KEY_SIZE) || \
(PSA_KEY_TYPE_IS_ECC(type) && size == (ECC_P256_PUB_KEY_SIZE + 1)) || \
(type == PSA_KEY_TYPE_HMAC && size == 32))
/**
* @brief Convert ATCA status values to PSA errors
*
* @param error
*
* @return @ref psa_status_t
*/
static psa_status_t atca_to_psa_error(ATCA_STATUS error)
{
switch (error) {
case ATCA_NOT_LOCKED:
case ATCA_EXECUTION_ERROR:
case ATCA_FUNC_FAIL:
return PSA_ERROR_BAD_STATE;
case ATCA_WAKE_FAILED:
case ATCA_RX_FAIL:
case ATCA_RX_NO_RESPONSE:
case ATCA_TX_TIMEOUT:
case ATCA_RX_TIMEOUT:
case ATCA_TOO_MANY_COMM_RETRIES:
case ATCA_COMM_FAIL:
case ATCA_TIMEOUT:
case ATCA_TX_FAIL:
return PSA_ERROR_COMMUNICATION_FAILURE;
case ATCA_RX_CRC_ERROR:
case ATCA_STATUS_CRC:
return PSA_ERROR_DATA_CORRUPT;
case ATCA_SMALL_BUFFER:
return PSA_ERROR_BUFFER_TOO_SMALL;
case ATCA_BAD_OPCODE:
case ATCA_BAD_PARAM:
case ATCA_INVALID_SIZE:
case ATCA_INVALID_ID:
return PSA_ERROR_INVALID_ARGUMENT;
case ATCA_UNIMPLEMENTED:
return PSA_ERROR_NOT_SUPPORTED;
default:
return PSA_ERROR_GENERIC_ERROR;
}
}
const char *atca_status_to_humanly_readable(ATCA_STATUS status)
{
switch (status) {
case ATCA_NOT_LOCKED:
return "ATCA_NOT_LOCKED";
case ATCA_EXECUTION_ERROR:
return "ATCA_EXECUTION_ERROR";
case ATCA_FUNC_FAIL:
return "ATCA_FUNC_FAIL";
case ATCA_WAKE_FAILED:
return "ATCA_WAKE_FAILED";
case ATCA_RX_FAIL:
return "ATCA_RX_FAIL";
case ATCA_RX_NO_RESPONSE:
return "ATCA_RX_NO_RESPONSE";
case ATCA_TX_TIMEOUT:
return "ATCA_TX_TIMEOUT";
case ATCA_RX_TIMEOUT:
return "ATCA_RX_TIMEOUT";
case ATCA_TOO_MANY_COMM_RETRIES:
return "ATCA_TOO_MANY_COMM_RETRIES";
case ATCA_COMM_FAIL:
return "ATCA_COMM_FAIL";
case ATCA_TIMEOUT:
return "ATCA_TIMEOUT";
case ATCA_TX_FAIL:
return "ATCA_TX_FAIL";
case ATCA_RX_CRC_ERROR:
return "ATCA_RX_CRC_ERROR";
case ATCA_STATUS_CRC:
return "ATCA_STATUS_CRC";
case ATCA_SMALL_BUFFER:
return "ATCA_SMALL_BUFFER";
case ATCA_BAD_OPCODE:
return "ATCA_BAD_OPCODE";
case ATCA_BAD_PARAM:
return "ATCA_BAD_PARAM";
case ATCA_INVALID_SIZE:
return "ATCA_INVALID_SIZE";
case ATCA_INVALID_ID:
return "ATCA_INVALID_ID";
case ATCA_UNIMPLEMENTED:
return "ATCA_UNIMPLEMENTED";
default:
return "Error value not recognized";
}
}
/* Secure Element Cipher Functions */
/**
* @brief Set up a driver specific AES CBC mode operation
*
* @param ctx
* @param dev
* @param key_slot
*/
static void atca_cbc_setup(atca_aes_cbc_ctx_t *ctx,
ATCADevice dev,
psa_key_slot_number_t key_slot)
{
ctx->device = dev;
ctx->key_id = key_slot;
ctx->key_block = 0;
}
psa_status_t atca_cipher_setup(psa_drv_se_context_t *drv_context,
void *op_context,
psa_key_slot_number_t key_slot,
psa_algorithm_t algorithm,
psa_encrypt_or_decrypt_t direction)
{
ATCADevice dev = (ATCADevice)drv_context->transient_data;
psa_se_cipher_context_t *ctx = (psa_se_cipher_context_t *)op_context;
/* Only device type ATECC608 supports AES operations */
if (dev->mIface.mIfaceCFG->devtype != ATECC608) {
DEBUG("ATCA Cipher Setup: Only ATECC608 devices support AES operations.\n");
return PSA_ERROR_NOT_SUPPORTED;
}
switch (algorithm) {
case PSA_ALG_CBC_NO_PADDING:
atca_cbc_setup(&ctx->drv_ctx.atca_aes_cbc, dev, key_slot);
break;
default:
DEBUG("ATCA Cipher Setup: Algorithm not supported by implementation.\n");
return PSA_ERROR_NOT_SUPPORTED;
}
ctx->direction = direction;
return PSA_SUCCESS;
}
psa_status_t atca_cipher_set_iv(void *op_context,
const uint8_t *p_iv,
size_t iv_length)
{
atca_aes_cbc_ctx_t *ctx = &((psa_se_cipher_context_t *)op_context)->drv_ctx.atca_aes_cbc;
if (iv_length != ATCA_MAX_IV_LEN) {
DEBUG("ATCA Cipher Set IV: Invalid IV length: Expected %d, was %d\n", \
ATCA_MAX_IV_LEN, iv_length);
return PSA_ERROR_INVALID_ARGUMENT;
}
memcpy(ctx->ciphertext, p_iv, iv_length);
return PSA_SUCCESS;
}
psa_status_t atca_cipher_update(void *op_context,
const uint8_t *p_input,
size_t input_size,
uint8_t *p_output,
size_t output_size,
size_t *p_output_length)
{
psa_se_cipher_context_t *ctx = (psa_se_cipher_context_t *)op_context;
ATCA_STATUS status = ATCA_EXECUTION_ERROR;
size_t offset = 0;
for (size_t data_block = 0; data_block < (input_size / AES_128_BLOCK_SIZE); data_block++) {
offset = data_block * AES_128_BLOCK_SIZE;
if (ctx->direction == PSA_CRYPTO_DRIVER_ENCRYPT) {
status = atcab_aes_cbc_encrypt_block(&ctx->drv_ctx.atca_aes_cbc, p_input + offset,
p_output + offset);
}
else {
status = atcab_aes_cbc_decrypt_block(&ctx->drv_ctx.atca_aes_cbc, p_input + offset,
p_output + offset);
}
if (status != ATCA_SUCCESS) {
DEBUG("ATCA Cipher Update failed. ATCA Error: %s\n",
atca_status_to_humanly_readable(status));
return atca_to_psa_error(status);
}
}
*p_output_length += input_size;
(void)output_size;
return PSA_SUCCESS;
}
psa_status_t atca_cipher_finish(void *op_context,
uint8_t *p_output,
size_t output_size,
size_t *p_output_length)
{
(void)op_context;
(void)p_output;
(void)output_size;
(void)p_output_length;
return PSA_SUCCESS;
}
psa_status_t atca_cipher_ecb(psa_drv_se_context_t *drv_context,
psa_key_slot_number_t key_slot,
psa_algorithm_t algorithm,
psa_encrypt_or_decrypt_t direction,
const uint8_t *p_input,
size_t input_size,
uint8_t *p_output,
size_t output_size)
{
ATCA_STATUS status;
ATCADevice dev = (ATCADevice)drv_context->transient_data;
size_t offset = 0;
if (dev->mIface.mIfaceCFG->devtype != ATECC608) {
DEBUG("ATCA Cipher ECB: Only ATECC608 devices support AES operations.\n");
return PSA_ERROR_NOT_SUPPORTED;
}
if (algorithm != PSA_ALG_ECB_NO_PADDING || direction != PSA_CRYPTO_DRIVER_ENCRYPT) {
DEBUG("ATCA Cipher ECB: Only AES ECB encryption without padding is supported.\n");
return PSA_ERROR_NOT_SUPPORTED;
}
if (input_size % AES_128_BLOCK_SIZE != 0) {
DEBUG("ATCA Cipher ECB: Input must be multiple of 16, was %d.\n", input_size);
return PSA_ERROR_INVALID_ARGUMENT;
}
do {
status = calib_aes_encrypt(dev, key_slot, 0, p_input + offset, p_output + offset);
if (status != ATCA_SUCCESS) {
DEBUG("ATCA Cipher ECB encrypt failed. ATCA Error: %s\n",
atca_status_to_humanly_readable(status));
return atca_to_psa_error(status);
}
offset += AES_128_BLOCK_SIZE;
} while (offset < input_size);
(void)output_size;
return PSA_SUCCESS;
}
/* Secure Element Key Management Functions */
psa_status_t atca_allocate(psa_drv_se_context_t *drv_context,
void *persistent_data,
const psa_key_attributes_t *attributes,
psa_key_creation_method_t method,
psa_key_slot_number_t *key_slot)
{
if (!ALG_IS_SUPPORTED(attributes->policy.alg)) {
DEBUG("ATCA allocate: Algorithm is not supported by device.\n");
return PSA_ERROR_NOT_SUPPORTED;
}
psa_key_type_t type = attributes->type;
psa_se_config_t *device_config = (psa_se_config_t *)persistent_data;
psa_atca_slot_config_t *slot_config = device_config->slots;
for (int i = 0; i < 16; i++) {
if (slot_config[i].key_type_allowed == type) {
/* If a slot is occupied, but the stored key is not marked as persistent,
we treat it as an empty slot and overwrite the key */
if (slot_config[i].slot_occupied && slot_config[i].key_persistent) {
continue;
}
*key_slot = i;
(&slot_config[i])->slot_occupied = 1;
DEBUG("Allocating slot %d for key type %x\n", (int)*key_slot, attributes->type);
if (PSA_KEY_LIFETIME_GET_PERSISTENCE(attributes->lifetime) != \
PSA_KEY_PERSISTENCE_VOLATILE) {
(&slot_config[i])->key_persistent = 1;
}
return PSA_SUCCESS;
}
}
(void)drv_context;
(void)method;
DEBUG("ATCA allocate: No free slot available.\n");
return PSA_ERROR_INSUFFICIENT_STORAGE;
}
psa_status_t atca_destroy(psa_drv_se_context_t *drv_context,
void *persistent_data,
psa_key_slot_number_t key_slot)
{
/**
* The ATECCX08A driver does not provide a key destruction function.
*
* This function just sets the `slot_occupied` flag in the driver's persistent
* data to 0, in case the key generation or import goes wrong, so the slot can
* be reused.
*/
psa_atca_slot_config_t *slot_config = (psa_atca_slot_config_t *)persistent_data;
DEBUG("Setting Key Slot %d to not occupied.\n", (int)key_slot);
(&slot_config[key_slot])->slot_occupied = 0;
(void)drv_context;
return PSA_SUCCESS;
}
psa_status_t atca_import(psa_drv_se_context_t *drv_context,
psa_key_slot_number_t key_slot,
const psa_key_attributes_t *attributes,
const uint8_t *data,
size_t data_length,
size_t *bits)
{
ATCA_STATUS status;
ATCADevice dev = (ATCADevice)drv_context->transient_data;
if (!ALG_IS_SUPPORTED(attributes->policy.alg)) {
DEBUG("ATCA import: Algorithm is not supported by device.\n");
return PSA_ERROR_NOT_SUPPORTED;
}
if (!KEY_SIZE_IS_SUPPORTED(data_length, attributes->type)) {
DEBUG("ATCA import: Key size is not supported by device.\n");
return PSA_ERROR_NOT_SUPPORTED;
}
if (PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(attributes->type)) {
status = calib_write_pubkey(dev, key_slot, data + 1);
if (status != ATCA_SUCCESS) {
DEBUG("ATCA Write Pubkey failed. ATCA Error: %s\n",
atca_status_to_humanly_readable(status));
return atca_to_psa_error(status);
}
*bits = PSA_BYTES_TO_BITS(data_length);
return PSA_SUCCESS;
}
else {
if (data_length > ATCA_WRITE_BUFFER_SIZE) {
DEBUG("ATCA import: Key size too large.\n");
return PSA_ERROR_INVALID_ARGUMENT;
}
uint8_t buf_in[ATCA_WRITE_BUFFER_SIZE] = { 0 };
/* AES keys can be written to slots in 32 or 64 byte chunks. For this we
copy them into a 32 byte buffer first and pad the empty bits with 0 */
memcpy(buf_in, data, data_length);
status = calib_write_bytes_zone(dev, ATCA_ZONE_DATA, key_slot, 0, buf_in, sizeof(buf_in));
if (status != ATCA_SUCCESS) {
DEBUG("ATCA Write AES key failed. ATCA Error: %s\n",
atca_status_to_humanly_readable(status));
return atca_to_psa_error(status);
}
*bits = PSA_BYTES_TO_BITS(data_length);
return PSA_SUCCESS;
}
DEBUG("ATCA import: Operation is not supported.\n");
return PSA_ERROR_NOT_SUPPORTED;
}
psa_status_t atca_generate_key(psa_drv_se_context_t *drv_context,
psa_key_slot_number_t key_slot,
const psa_key_attributes_t *attributes,
uint8_t *pubkey, size_t pubkey_size, size_t *pubkey_length)
{
ATCA_STATUS status;
ATCADevice dev = (ATCADevice)drv_context->transient_data;
if (!PSA_KEY_TYPE_IS_ECC(attributes->type)) {
DEBUG("ATCA Generate Key: Only ECC key generation is supported.\n");
return PSA_ERROR_NOT_SUPPORTED;
}
if (pubkey_size > PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(attributes->type, attributes->bits)) {
DEBUG("ATCA Generate Key: Pubkey size not supported. Expected %d, was %d.\n", \
PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(attributes->type, attributes->bits), pubkey_size);
return PSA_ERROR_NOT_SUPPORTED;
}
if (pubkey != NULL) {
/**
* PSA supports the uncompressed binary format to encode ECC public keys.
* This means, that both the x and y coordinate are stored.
* This format is encoded by adding an extra byte containing the value 0x04
* (see also "Technical Guideline BSI TR-03111").
*
* The ATECCX08A stores and exports the x and y coordinate, so all we need to do is
* add the byte before the coordinates.
*/
pubkey[0] = 0x04;
*pubkey_length = PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(attributes->type, attributes->bits);
status = calib_genkey(dev, key_slot, &pubkey[1]);
}
else {
status = calib_genkey(dev, key_slot, NULL);
}
if (status != ATCA_SUCCESS) {
DEBUG("ATCA Genkey failed. ATCA Error: %s\n",
atca_status_to_humanly_readable(status));
return atca_to_psa_error(status);
}
return PSA_SUCCESS;
}
psa_status_t atca_export_public_key(psa_drv_se_context_t *drv_context,
psa_key_slot_number_t key_slot,
uint8_t *p_data,
size_t data_size,
size_t *p_data_length)
{
ATCA_STATUS status;
ATCADevice dev = (ATCADevice)drv_context->transient_data;
if (data_size < ECC_P256_PUB_KEY_SIZE) {
DEBUG("ATCA Export public key: Buffer too small, expected %d, was %d\n", \
ECC_P256_PUB_KEY_SIZE, data_size);
return PSA_ERROR_BUFFER_TOO_SMALL;
}
status = calib_get_pubkey(dev, key_slot, &p_data[1]);
if (status != ATCA_SUCCESS) {
DEBUG("ATCA Get Pubkey failed. ATCA Error: %s\n",
atca_status_to_humanly_readable(status));
return atca_to_psa_error(status);
}
/**
* PSA supports the uncompressed binary format to encode ECC public keys.
* This means, that both the x and y coordinate are stored.
* This format is encoded by adding an extra byte containing the value 0x04
* (see also "Technical Guideline BSI TR-03111").
*
* The ATECCX08A stored and exports the x and y coordinate, so all we need to do is
* add the byte before the coordinates.
*/
p_data[0] = 0x04;
/* Since we added the encoding byte, the stored public key is now 65 bytes long instead of 64 */
*p_data_length = ECC_P256_PUB_KEY_SIZE + 1;
return PSA_SUCCESS;
}
psa_status_t atca_sign(psa_drv_se_context_t *drv_context,
psa_key_slot_number_t key_slot,
psa_algorithm_t alg,
const uint8_t *p_hash,
size_t hash_length,
uint8_t *p_signature,
size_t signature_size,
size_t *p_signature_length)
{
ATCA_STATUS status;
ATCADevice dev = (ATCADevice)drv_context->transient_data;
if (alg != PSA_ALG_ECDSA(PSA_ALG_SHA_256)) {
DEBUG("ATCA Sign: Only ECDSA with SHA256 Messages is supported.\n");
return PSA_ERROR_NOT_SUPPORTED;
}
if ((signature_size != ECC_P256_PUB_KEY_SIZE) || \
(hash_length != PSA_HASH_LENGTH(PSA_ALG_SHA_256))) {
DEBUG("ATCA Sign: Invalid signature or hash size. Expected Sig: %d |\
Hash %d, were Sig: %d | Hash: %d\n",\
ECC_P256_PUB_KEY_SIZE, PSA_HASH_LENGTH(PSA_ALG_SHA_256),\
signature_size, hash_length);
return PSA_ERROR_INVALID_ARGUMENT;
}
status = calib_sign(dev, key_slot, p_hash, p_signature);
if (status != ATCA_SUCCESS) {
DEBUG("ATCA Sign failed. ATCA Error: %s\n",
atca_status_to_humanly_readable(status));
return atca_to_psa_error(status);
}
*p_signature_length = signature_size;
return PSA_SUCCESS;
}
psa_status_t atca_verify(psa_drv_se_context_t *drv_context,
psa_key_slot_number_t key_slot,
psa_algorithm_t alg,
const uint8_t *p_hash,
size_t hash_length,
const uint8_t *p_signature,
size_t signature_length)
{
ATCA_STATUS status;
ATCADevice dev = (ATCADevice)drv_context->transient_data;
bool is_verified;
/* We only support the operation on public keys, if they're stored on a device. */
if (alg != PSA_ALG_ECDSA(PSA_ALG_SHA_256)) {
DEBUG("ATCA Verify: Only ECDSA with SHA256 Messages is supported.\n");
return PSA_ERROR_NOT_SUPPORTED;
}
if ((signature_length != ECC_P256_PUB_KEY_SIZE) || \
(hash_length != PSA_HASH_LENGTH(PSA_ALG_SHA_256))) {
DEBUG("ATCA Sign: Invalid signature or hash size. Expected Sig: %d |\
Hash %d, were Sig: %d | Hash: %d\n",\
ECC_P256_PUB_KEY_SIZE, PSA_HASH_LENGTH(PSA_ALG_SHA_256),\
signature_length, hash_length);
return PSA_ERROR_INVALID_ARGUMENT;
}
status = calib_verify_stored(dev, p_hash, p_signature, key_slot, &is_verified);
if (status != ATCA_SUCCESS) {
DEBUG("ATCA Verify failed. ATCA Error: %s\n",
atca_status_to_humanly_readable(status));
return atca_to_psa_error(status);
}
return is_verified ? PSA_SUCCESS : PSA_ERROR_INVALID_SIGNATURE;
}
psa_status_t atca_generate_mac(psa_drv_se_context_t *drv_context,
const uint8_t *p_input,
size_t input_length,
psa_key_slot_number_t key_slot,
psa_algorithm_t alg,
uint8_t *p_mac,
size_t mac_size,
size_t *p_mac_length)
{
ATCA_STATUS status;
ATCADevice dev = (ATCADevice)drv_context->transient_data;
if (!PSA_ALG_IS_HMAC(alg)) {
DEBUG("ATCA Generate MAC: Only HMAC SHA256 is supported.\n");
return PSA_ERROR_NOT_SUPPORTED;
}
if (mac_size < PSA_HASH_LENGTH(PSA_ALG_SHA_256)) {
DEBUG("ATCA Generate Mac: Buffer too small, expected %d, was %d\n", \
PSA_HASH_LENGTH(PSA_ALG_SHA_256), mac_size);
return PSA_ERROR_BUFFER_TOO_SMALL;
}
status = calib_sha_hmac(dev, p_input, input_length, key_slot, p_mac, SHA_MODE_TARGET_OUT_ONLY);
if (status != ATCA_SUCCESS) {
DEBUG("ATCA SHA HMAC failed. ATCA Error: %s\n",
atca_status_to_humanly_readable(status));
return atca_to_psa_error(status);
}
*p_mac_length = PSA_HASH_LENGTH(PSA_ALG_SHA_256);
return PSA_SUCCESS;
}
static psa_drv_se_mac_t atca_mac = {
.context_size = 0,
.p_setup = NULL,
.p_update = NULL,
.p_finish = NULL,
.p_finish_verify = NULL,
.p_abort = NULL,
.p_mac = atca_generate_mac,
.p_mac_verify = NULL,
};
static psa_drv_se_cipher_t atca_cipher = {
.context_size = 0,
.p_setup = atca_cipher_setup,
.p_set_iv = atca_cipher_set_iv,
.p_update = atca_cipher_update,
.p_finish = atca_cipher_finish,
.p_abort = NULL,
.p_ecb = atca_cipher_ecb
};
static psa_drv_se_key_management_t atca_key_management = {
.p_allocate = atca_allocate,
.p_validate_slot_number = NULL,
.p_import = atca_import,
.p_generate = atca_generate_key,
.p_destroy = atca_destroy,
.p_export = NULL,
.p_export_public = atca_export_public_key
};
static psa_drv_se_asymmetric_t atca_asymmetric = {
.p_sign = atca_sign,
.p_verify = atca_verify,
.p_encrypt = NULL,
.p_decrypt = NULL
};
psa_drv_se_t atca_methods = {
.hal_version = PSA_DRV_SE_HAL_VERSION,
.persistent_data_size = 0,
.p_init = NULL,
.key_management = &atca_key_management,
.mac = &atca_mac,
.cipher = &atca_cipher,
.aead = NULL,
.asymmetric = &atca_asymmetric,
.derivation = NULL
};

View File

@ -0,0 +1,19 @@
# Copyright (c) 2020 HAW Hamburg
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
config PACKAGE_DRIVER_CRYPTOCELL_310
bool
depends on CPU_MODEL_NRF52840XXAA
depends on TEST_KCONFIG
depends on HAS_PERIPH_CRYPTOCELL_310
depends on MODULE_PERIPH_CRYPTOCELL_310
select MODULE_DRIVER_CRYPTOCELL_310_CONTRIB
config MODULE_DRIVER_CRYPTOCELL_310_CONTRIB
bool
rsource "psa_cryptocell_310/Kconfig"

View File

@ -0,0 +1,36 @@
PKG_NAME=driver_cryptocell_310
PKG_URL=https://www.nordicsemi.com/-/media/Software-and-other-downloads/SDKs/nRF5/Binaries
PKG_VERSION=17.1.0
PKG_EXT=zip
PKG_DIR_NAME=nRF5_SDK_17.1.0_ddde560
PKG_LICENSE=ARM Object Code and Header Files License
PKG_SOURCE_DIR ?= $(PKGDIRBASE)/$(PKG_NAME)
NRF_CC310_PATH = $(PKG_DIR_NAME)/external/nrf_cc310
PKG_ZIPFILE = $(PKG_DIR_NAME).$(PKG_EXT)
ifneq ($(RIOTBASE),)
include $(RIOTBASE)/Makefile.base
endif
.PHONY: all clean distclean prepare
prepare: $(PKG_PREPARED)
@:
all: $(PKGDIRBASE)/$(PKG_ZIPFILE)
$(Q)$(UNZIP_HERE) -D -n -d $(PKGDIRBASE) $(PKGDIRBASE)/$(PKG_ZIPFILE)
$(Q) mkdir -p $(PKG_SOURCE_DIR)/include
$(Q)cp $(PKGDIRBASE)/$(NRF_CC310_PATH)/include/* $(PKG_SOURCE_DIR)/include
$(Q)cp $(PKGDIRBASE)/$(NRF_CC310_PATH)/lib/cortex-m4/hard-float/libnrf_cc310_0.9.13.a $(PKG_SOURCE_DIR)
$(Q)rm -rf $(PKGDIRBASE)/$(PKG_DIR_NAME)
$(PKGDIRBASE)/$(PKG_ZIPFILE):
$(QQ)mkdir -p $(PKGDIRBASE)
$(Q)$(DOWNLOAD_TO_FILE) $(PKGDIRBASE)/$(PKG_ZIPFILE) $(PKG_URL)/$(PKG_ZIPFILE)
clean::
rm -rf $(PKG_SOURCE_DIR)
distclean::
rm -rf $(PKG_SOURCE_DIR) $(PKGDIRBASE)/$(PKG_ZIPFILE)

View File

@ -0,0 +1,6 @@
USEMODULE += driver_cryptocell_310_contrib
FEATURES_REQUIRED += periph_cryptocell_310
ifneq (,$(filter psa_cryptocell_310_%,$(USEMODULE)))
include $(RIOTPKG)/driver_cryptocell_310/psa_cryptocell_310/Makefile.dep
endif

View File

@ -0,0 +1,25 @@
INCLUDES += -I$(PKGDIRBASE)/driver_cryptocell_310/include
INCLUDES += -I$(RIOTPKG)/driver_cryptocell_310/include
DIRS += $(RIOTPKG)/driver_cryptocell_310/contrib
ARCHIVES += $(PKGDIRBASE)/driver_cryptocell_310/libnrf_cc310_0.9.13.a
ifneq (,$(filter psa_cryptocell_310_%, $(USEMODULE)))
DIRS += $(RIOTPKG)/driver_cryptocell_310/psa_cryptocell_310
INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include
endif
CFLAGS += -Wno-cast-align
PSEUDOMODULES += psa_cryptocell_310_aes_cbc
PSEUDOMODULES += psa_cryptocell_310_aes_common
PSEUDOMODULES += psa_cryptocell_310_ecc_common
PSEUDOMODULES += psa_cryptocell_310_ecc_p192
PSEUDOMODULES += psa_cryptocell_310_ecc_p256
PSEUDOMODULES += psa_cryptocell_310_error_conversion
PSEUDOMODULES += psa_cryptocell_310_hashes_common
PSEUDOMODULES += psa_cryptocell_310_hashes_sha1
PSEUDOMODULES += psa_cryptocell_310_hashes_sha224
PSEUDOMODULES += psa_cryptocell_310_hashes_sha256
PSEUDOMODULES += psa_cryptocell_310_hashes_sha512
PSEUDOMODULES += psa_cryptocell_310_hmac

View File

@ -0,0 +1,3 @@
MODULE = driver_cryptocell_310_contrib
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,83 @@
/*
* Copyright (C) 2020 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pkg_driver_cryptocell_310
* @{
*
* @file
* @brief Setup function necessary to enable ARM CryptoCell module
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*/
#include "vendor/nrf52840.h"
#include "sns_silib.h"
#include "kernel_defines.h"
#define ENABLE_DEBUG 0
#include "debug.h"
CRYS_RND_WorkBuff_t *rndWorkBuff_ptr;
CRYS_RND_State_t *rndState_ptr;
CRYS_RND_State_t rndState = { 0 };
CRYS_RND_WorkBuff_t rndWorkBuff = { 0 };
/* Defined by the CryptoCell Library */
extern void CRYPTOCELL_IRQHandler(void);
/* This function must be defined to use the CryptoCell module on the NRF52840 board */
void isr_cryptocell(void)
{
CRYPTOCELL_IRQHandler();
}
void cryptocell_310_enable(void)
{
NRF_CRYPTOCELL->ENABLE = 1;
NVIC_EnableIRQ(CRYPTOCELL_IRQn);
}
void cryptocell_310_disable(void)
{
NRF_CRYPTOCELL->ENABLE = 0;
NVIC_DisableIRQ(CRYPTOCELL_IRQn);
}
void driver_cryptocell_310_setup(void)
{
int ret = 0;
rndState_ptr = &rndState;
rndWorkBuff_ptr = &rndWorkBuff;
cryptocell_310_enable();
ret = SaSi_LibInit();
if (ret != SA_SILIB_RET_OK) {
DEBUG("SaSi_LibInit failed: 0x%x\n", ret);
}
ret = CRYS_RndInit(rndState_ptr, rndWorkBuff_ptr);
if (ret != SA_SILIB_RET_OK) {
DEBUG("CRYS_RndInit failed: 0x%x\n", ret);
}
}
void driver_cryptocell_310_terminate(void)
{
int ret = 0;
SaSi_LibFini();
ret = CRYS_RND_UnInstantiation(rndState_ptr);
if (ret != SA_SILIB_RET_OK) {
DEBUG("CRYS_RND_UnInstatiation failed: 0x%x\n", ret);
}
}

View File

@ -0,0 +1,10 @@
/**
* @defgroup pkg_driver_cryptocell_310 ARM CryptoCell 310 Driver
* @ingroup pkg drivers_misc
* @brief Provides the driver for the ARM CryptoCell 310 hardware accelerator
* @see https://infocenter.nordicsemi.com/topic/sdk_nrf5_v17.1.0/group__cryptocell__api.html
*
* @note The source of this package is not a git repository, but a zip file downloaded
* from the Nordic Semiconductor software center. It is quite large and takes a
* while to download.
*/

View File

@ -0,0 +1,3 @@
MODULE = driver_cryptocell_310
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pkg_driver_cryptocell_310
* @{
*
* @file
* @brief Utility functions to setup and terminate the CryptoCell 310 driver
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef CRYPTOCELL_310_UTIL_H
#define CRYPTOCELL_310_UTIL_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Enable CryptoCell module and IRQs.
*
* Must be called before using crypto functions.
* CryptoCell peripheral will be enabled after this call.
*/
void cryptocell_310_enable(void);
/**
* @brief Disable CryptoCell module and IRQs.
*
* Should be called after using crypto functions.
* CryptoCell peripheral will be disabled after this call.
*/
void cryptocell_310_disable(void);
/**
* @brief Enables CryptoCell module, IRQs and crypto libraries on nrf52840.
*
* Must be called once before using the CryptoCell lib.
*/
void driver_cryptocell_310_setup(void);
/**
* @brief Finishes the use of the CryptoCell library.
*
* Should be called after using the CryptoCell lib.
*/
void driver_cryptocell_310_terminate(void);
#ifdef __cplusplus
}
#endif
#endif /* CRYPTOCELL_310_UTIL_H */
/** @} */

View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pkg_driver_cryptocell_310
* @{
*
* @file
* @brief Common AES functions used by all PSA Crypto wrappers
* for the CryptoCell 310 AES APIs.
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef PSA_CRYPTOCELL_310_AES_COMMON_H
#define PSA_CRYPTOCELL_310_AES_COMMON_H
#ifdef __cplusplus
extern "C" {
#endif
#include "psa/crypto.h"
/**
* @brief Common setup function for AES operations
*
* @param ctx Driver specific AES context of the type @c SaSiAesUserContext_t
* @param direction Encrypt or decrypt direction of type @c SaSiAesEncryptMode_t
* @param mode Operation mode (e.g. CBC, CCM) of type @c SaSiAesOperationMode_t
* @param padding Operation padding type of type @c SaSiAesPaddingType_t
* @param iv Constant buffer containing the IV for the operation
* @param key_buffer Constant buffer containing an AES key
* @param key_size Size of AES key in use.
* @return psa_status_t
*/
psa_status_t cryptocell_310_common_aes_setup(SaSiAesUserContext_t *ctx,
SaSiAesEncryptMode_t direction,
SaSiAesOperationMode_t mode,
SaSiAesPaddingType_t padding,
const uint8_t *iv,
const uint8_t *key_buffer,
size_t key_size);
/**
* @brief Common function for an AES encryption
*
* @param ctx AES context of the type @c SaSiAesUserContext_t
* @param input Constant input buffer of plain text to encrypt
* @param input_length Length of the input buffer
* @param output Output buffer to write the cipher
* @param output_buffer_size Size of the output buffer. Must be at least @c input_length
* @param output_length Pointer to output length. Will contain actual length of cipher
* @return psa_status_t
*/
psa_status_t cryptocell_310_common_aes_encrypt_decrypt(SaSiAesUserContext_t *ctx,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_buffer_size,
size_t *output_length);
#ifdef __cplusplus
}
#endif
#endif /* PSA_CRYPTOCELL_310_AES_COMMON_H */
/** @} */

View File

@ -0,0 +1,115 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pkg_driver_cryptocell_310
* @{
*
* @file
* @brief Common ECC functions used by all PSA Crypto wrappers
* for the CryptoCell 310 ECC APIs.
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef PSA_CRYPTOCELL_310_ECC_COMMON_H
#define PSA_CRYPTOCELL_310_ECC_COMMON_H
#ifdef __cplusplus
extern "C" {
#endif
#include "psa/crypto.h"
#include "sns_silib.h"
#include "crys_ecpki_build.h"
#include "crys_ecpki_ecdsa.h"
#include "crys_ecpki_kg.h"
#include "crys_ecpki_domain.h"
/**
* @brief Map PSA hash encodings to CryptoCell specific hash encodings
*
* @param hash psa_algorithm_t
*/
#define MAP_PSA_HASH_TO_CRYS_HASH(hash) \
((hash == PSA_ALG_SHA_1) ? CRYS_ECPKI_AFTER_HASH_SHA1_mode : \
(hash == PSA_ALG_SHA_224) ? CRYS_ECPKI_AFTER_HASH_SHA224_mode : \
(hash == PSA_ALG_SHA_256) ? CRYS_ECPKI_AFTER_HASH_SHA256_mode : \
(hash == PSA_ALG_SHA_384) ? CRYS_ECPKI_AFTER_HASH_SHA384_mode : \
(hash == PSA_ALG_SHA_512) ? CRYS_ECPKI_AFTER_HASH_SHA512_mode : \
0)
/**
* @brief Common ECC key generation function
*
* @param priv_key_buffer Output buffer to write ECC private key
* @param pub_key_buffer Output buffer to write ECC public key
* @param priv_key_buffer_length Output pointer to write private key length
* @param pub_key_buffer_length Output pointer to write public key length
* @param domain ECC domain of type @c CRYS_ECPKI_DomainID_t
* @return psa_status_t
*/
psa_status_t cryptocell_310_common_ecc_generate_key_pair(uint8_t *priv_key_buffer,
uint8_t *pub_key_buffer,
uint32_t *priv_key_buffer_length,
uint32_t *pub_key_buffer_length,
CRYS_ECPKI_DomainID_t domain);
/**
* @brief Common ECC hash signature function
*
* @param priv_key Pointer to ECC private key
* @param priv_key_size Size of private key
* @param hash Hash of the message to sign
* @param hash_length Length of the message hash
* @param signature Output buffer to write the generated signature
* @param signature_length Pointer to store the actual length of the signature
* @param hash_mode Mode used to hash the message of type @c CRYS_ECPKI_HASH_OpMode_t
* @param domain ECC domain of type @c CRYS_ECPKI_DomainID_t
* @return psa_status_t
*/
psa_status_t cryptocell_310_common_ecc_sign_hash(const uint8_t *priv_key,
uint32_t priv_key_size,
const uint8_t *hash,
size_t hash_length,
uint8_t *signature,
size_t *signature_length,
CRYS_ECPKI_HASH_OpMode_t hash_mode,
CRYS_ECPKI_DomainID_t domain);
/**
* @brief Common ECC hash verification function
*
* @param pub_key Pointer to ECC public key
* @param pub_key_size Size of public key
* @param hash Hash of the message to sign
* @param hash_length Length of the message hash
* @param signature Buffer containing the signature to be verified
* @param signature_length Actual length of the signature
* @param hash_mode Mode used to hash the message of type
* @c CRYS_ECPKI_HASH_OpMode_t
* @param domain ECC domain of type @c CRYS_ECPKI_DomainID_t
* @return psa_status_t
*/
psa_status_t cryptocell_310_common_ecc_verify_hash(const uint8_t *pub_key,
size_t pub_key_size,
const uint8_t *hash,
size_t hash_length,
const uint8_t *signature,
size_t signature_length,
CRYS_ECPKI_HASH_OpMode_t hash_mode,
CRYS_ECPKI_DomainID_t domain);
#ifdef __cplusplus
}
#endif
#endif /* PSA_CRYPTOCELL_310_ECC_COMMON_H */
/** @} */

View File

@ -0,0 +1,71 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pkg_driver_cryptocell_310
* @{
*
* @file
* @brief Common hash functions used by all PSA Crypto wrappers
* for the CryptoCell 310 hash APIs.
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef PSA_CRYPTOCELL_310_HASHES_COMMON_H
#define PSA_CRYPTOCELL_310_HASHES_COMMON_H
#ifdef __cplusplus
extern "C" {
#endif
#include "psa/crypto.h"
#include "crys_hash.h"
/**
* @brief Common hash setup function
*
* @param ctx Driver specific hash context of type @c CRYS_HASHUserContext_t
* @param mode Hash mode of type @c CRYS_HASH_OperationMode_t
* @return psa_status_t
*/
psa_status_t cryptocell_310_common_hash_setup(CRYS_HASHUserContext_t *ctx,
CRYS_HASH_OperationMode_t mode);
/**
* @brief Common hash update function
*
* @param ctx Driver specific hash context of type @c CRYS_HASHUserContext_t
* @param input Input that is going to be hashed
* @param input_length Length of @p input
* @return psa_status_t
*/
psa_status_t cryptocell_310_common_hash_update(CRYS_HASHUserContext_t *ctx,
const uint8_t *input,
size_t input_length);
/**
* @brief Common hash finish function
*
* @param ctx Driver specific hash context of type @c CRYS_HASHUserContext_t
* @param hash Output buffer to write the computated hash
* @param hash_size Size of @p hash
* @param hash_length Pointer where the actual length of the hash will be stored
* @return psa_status_t
*/
psa_status_t cryptocell_310_common_hash_finish(CRYS_HASHUserContext_t *ctx,
uint8_t *hash,
size_t hash_size,
size_t *hash_length);
#ifdef __cplusplus
}
#endif
#endif /* PSA_CRYPTOCELL_310_HASHES_COMMON_H */
/** @} */

View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pkg_driver_cryptocell_310
* @{
*
* @file
* @brief Glue code translating between PSA Crypto and the CryptoCell 310 driver APIs
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef PSA_ERROR_H
#define PSA_ERROR_H
#ifdef __cplusplus
extern "C" {
#endif
#include "psa/crypto.h"
#include "crys_ecpki_error.h"
#include "crys_hash_error.h"
#include "ssi_aes_error.h"
/**
* @brief Convert CryptoCell CRYS errors to PSA status values
*
* @param error Error value of type @c CRYSError_t
* @return @ref psa_status_t
*/
psa_status_t CRYS_to_psa_error(CRYSError_t error);
/**
* @brief Convert CryptoCell SaSi errors to PSA status values
*
* @param error Error value of type @c SaSiStatus
* @return @ref psa_status_t
*/
psa_status_t SaSi_to_psa_error(SaSiStatus error);
/**
* @brief Function to print CryptoCell Error values in clear text.
*
* @param status Error value of type @c SaSiStatus or @c CRYSError_t
* @return const char*
*/
const char *cryptocell310_status_to_humanly_readable(uint32_t status);
#ifdef __cplusplus
}
#endif
#endif /* PSA_ERROR_H */
/** @} */

View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pkg_driver_cryptocell_310
* @{
*
* @file
* @brief CryptoCell 310 driver specific AES contexts
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef PSA_PERIPH_AES_CTX_H
#define PSA_PERIPH_AES_CTX_H
#ifdef __cplusplus
extern "C" {
#endif
#include "ssi_aes.h"
#include "kernel_defines.h"
#if IS_USED(MODULE_PERIPH_CIPHER_AES_128_CBC) || DOXYGEN
/**
* @brief Map driver specific AES context to PSA context
*/
typedef SaSiAesUserContext_t psa_cipher_aes_128_ctx_t;
#endif
#ifdef __cplusplus
}
#endif
#endif /* PSA_PERIPH_AES_CTX_H */
/** @} */

View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pkg_driver_cryptocell_310
* @{
*
* @file
* @brief CryptoCell 310 driver specific hash contexts
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef PSA_PERIPH_HASHES_CTX_H
#define PSA_PERIPH_HASHES_CTX_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#include "kernel_defines.h"
#include "crys_hash.h"
#if IS_USED(MODULE_PERIPH_HASH_SHA_1) || DOXYGEN
/**
* @brief Map driver specific SHA1 context to PSA context
*/
typedef CRYS_HASHUserContext_t psa_hashes_sha1_ctx_t;
#endif
#if IS_USED(MODULE_PERIPH_HASH_SHA_224) || DOXYGEN
/**
* @brief Map driver specific SHA224 context to PSA context
*/
typedef CRYS_HASHUserContext_t psa_hashes_sha224_ctx_t;
#endif
#if IS_USED(MODULE_PERIPH_HASH_SHA_256) || DOXYGEN
/**
* @brief Map driver specific SHA256 context to PSA context
*/
typedef CRYS_HASHUserContext_t psa_hashes_sha256_ctx_t;
#endif
#if IS_USED(MODULE_PERIPH_HASH_SHA_512) || DOXYGEN
/**
* @brief Map driver specific SHA512 context to PSA context
*/
typedef CRYS_HASHUserContext_t psa_hashes_sha512_ctx_t;
#endif
#ifdef __cplusplus
}
#endif
#endif /* PSA_PERIPH_HASHES_CTX_H */
/** @} */

View File

@ -0,0 +1,77 @@
# Copyright (c) 2021 HAW Hamburg
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
# Hashes
config MODULE_PSA_CRYPTOCELL_310_HASHES_SHA1
bool
depends on MODULE_PSA_CRYPTO
select MODULE_PSA_CRYPTOCELL_310
select MODULE_PSA_CRYPTOCELL_310_HASHES_COMMON
config MODULE_PSA_CRYPTOCELL_310_HASHES_SHA224
bool
depends on MODULE_PSA_CRYPTO
select MODULE_PSA_CRYPTOCELL_310
select MODULE_PSA_CRYPTOCELL_310_HASHES_COMMON
config MODULE_PSA_CRYPTOCELL_310_HASHES_SHA256
bool
depends on MODULE_PSA_CRYPTO
select MODULE_PSA_CRYPTOCELL_310
select MODULE_PSA_CRYPTOCELL_310_HASHES_COMMON
config MODULE_PSA_CRYPTOCELL_310_HASHES_SHA512
bool
depends on MODULE_PSA_CRYPTO
select MODULE_PSA_CRYPTOCELL_310
select MODULE_PSA_CRYPTOCELL_310_HASHES_COMMON
# MAC
config MODULE_PSA_CRYPTOCELL_310_HMAC
bool
depends on MODULE_PSA_CRYPTO
select MODULE_PSA_CRYPTOCELL_310
# AES
config MODULE_PSA_CRYPTOCELL_310_AES_CBC
bool
depends on MODULE_PSA_CRYPTO
select MODULE_PSA_CRYPTOCELL_310
select MODULE_PSA_CRYPTOCELL_310_AES_COMMON
# ECC
config MODULE_PSA_CRYPTOCELL_310_ECC_P192
bool
depends on MODULE_PSA_CRYPTO
select MODULE_PSA_CRYPTOCELL_310
select MODULE_PSA_CRYPTOCELL_310_ECC_COMMON
config MODULE_PSA_CRYPTOCELL_310_ECC_P256
bool
depends on MODULE_PSA_CRYPTO
select MODULE_PSA_CRYPTOCELL_310
select MODULE_PSA_CRYPTOCELL_310_ECC_COMMON
config MODULE_PSA_CRYPTOCELL_310
bool "PSA CryptoCell Wrapper"
select MODULE_PSA_CRYPTOCELL_310_ERROR_CONVERSION
config MODULE_PSA_CRYPTOCELL_310_HASHES_COMMON
bool
config MODULE_PSA_CRYPTOCELL_310_ECC_COMMON
bool
config MODULE_PSA_CRYPTOCELL_310_AES_COMMON
bool
config MODULE_PSA_CRYPTOCELL_310_ERROR_CONVERSION
bool

View File

@ -0,0 +1,4 @@
BASE_MODULE := psa_cryptocell_310
SUBMODULES := 1
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,30 @@
USEMODULE += psa_cryptocell_310
USEMODULE += psa_cryptocell_310_error_conversion
ifneq (,$(filter psa_cryptocell_310_hashes_sha1,$(USEMODULE)))
USEMODULE += psa_cryptocell_310_hashes_common
endif
ifneq (,$(filter psa_cryptocell_310_hashes_sha224,$(USEMODULE)))
USEMODULE += psa_cryptocell_310_hashes_common
endif
ifneq (,$(filter psa_cryptocell_310_hashes_sha256,$(USEMODULE)))
USEMODULE += psa_cryptocell_310_hashes_common
endif
ifneq (,$(filter psa_cryptocell_310_hashes_sha512,$(USEMODULE)))
USEMODULE += psa_cryptocell_310_hashes_common
endif
ifneq (,$(filter psa_cryptocell_310_aes_cbc,$(USEMODULE)))
USEMODULE += psa_cryptocell_310_aes_common
endif
ifneq (,$(filter psa_cryptocell_310_ecc_p192,$(USEMODULE)))
USEMODULE += psa_cryptocell_310_ecc_common
endif
ifneq (,$(filter psa_cryptocell_310_ecc_p256,$(USEMODULE)))
USEMODULE += psa_cryptocell_310_ecc_common
endif

View File

@ -0,0 +1,131 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pkg_driver_cryptocell_310
* @{
*
* @brief Glue code translating between PSA Crypto and the CryptoCell 310 AES 128 CBC APIs
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include "psa_error.h"
#include "psa_cryptocell_310_aes_common.h"
#include "ssi_aes.h"
#define ENABLE_DEBUG 0
#include "debug.h"
psa_status_t psa_cipher_cbc_aes_128_encrypt(const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
if ((alg != PSA_ALG_CBC_PKCS7) && (alg != PSA_ALG_CBC_NO_PADDING)) {
DEBUG("%s : Invalid CBC padding type\n", __FILE__);
return PSA_ERROR_INVALID_ARGUMENT;
}
if (key_buffer_size < PSA_BITS_TO_BYTES(attributes->bits)) {
DEBUG("%s : Key buffer too small\n", __FILE__);
return PSA_ERROR_BUFFER_TOO_SMALL;
}
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
size_t iv_length = 0;
size_t key_size = PSA_BITS_TO_BYTES(attributes->bits);
psa_cipher_operation_t operation = psa_cipher_operation_init();
operation.iv_required = 1;
operation.default_iv_length = PSA_CIPHER_IV_LENGTH(attributes->type, alg);
SaSiAesPaddingType_t padding =
(alg == PSA_ALG_CBC_PKCS7) ? SASI_AES_PADDING_PKCS7 : SASI_AES_PADDING_NONE;
status = psa_cipher_generate_iv(&operation, output, operation.default_iv_length, &iv_length);
if (status != PSA_SUCCESS) {
return status;
}
status = cryptocell_310_common_aes_setup((SaSiAesUserContext_t *)&operation.backend_ctx.cipher_ctx.aes_128,
SASI_AES_ENCRYPT, SASI_AES_MODE_CBC, padding, output, key_buffer,
key_size);
if (status != PSA_SUCCESS) {
return status;
}
status = cryptocell_310_common_aes_encrypt_decrypt(
(SaSiAesUserContext_t *)&operation.backend_ctx.cipher_ctx.aes_128,
input, input_length, output + iv_length, output_size - iv_length,
output_length);
if (status != PSA_SUCCESS) {
return status;
}
*output_length = output_size;
return PSA_SUCCESS;
}
psa_status_t psa_cipher_cbc_aes_128_decrypt(const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
if ((alg != PSA_ALG_CBC_PKCS7) && (alg != PSA_ALG_CBC_NO_PADDING)) {
DEBUG("%s : Invalid CBC padding type\n", __FILE__);
return PSA_ERROR_INVALID_ARGUMENT;
}
if (key_buffer_size < PSA_BITS_TO_BYTES(attributes->bits)) {
DEBUG("%s : Key buffer too small\n", __FILE__);
return PSA_ERROR_BUFFER_TOO_SMALL;
}
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
size_t key_size = PSA_BITS_TO_BYTES(attributes->bits);
psa_cipher_operation_t operation = psa_cipher_operation_init();
operation.iv_required = 1;
operation.default_iv_length = PSA_CIPHER_IV_LENGTH(attributes->type, alg);
SaSiAesPaddingType_t padding =
(alg == PSA_ALG_CBC_PKCS7) ? SASI_AES_PADDING_PKCS7 : SASI_AES_PADDING_NONE;
status = cryptocell_310_common_aes_setup((SaSiAesUserContext_t *)&operation.backend_ctx.cipher_ctx.aes_128,
SASI_AES_DECRYPT, SASI_AES_MODE_CBC, padding, input, key_buffer,
key_size);
if (status != PSA_SUCCESS) {
return status;
}
status = cryptocell_310_common_aes_encrypt_decrypt(
(SaSiAesUserContext_t *)&operation.backend_ctx.cipher_ctx.aes_128,
input + operation.default_iv_length, input_length - operation.
default_iv_length, output, output_size, output_length);
if (status != PSA_SUCCESS) {
return status;
}
*output_length = PSA_CIPHER_DECRYPT_OUTPUT_SIZE(attributes->type, alg, input_length);
return PSA_SUCCESS;
}

View File

@ -0,0 +1,112 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pkg_driver_cryptocell_310
* @{
*
* @brief Common AES functions used by all PSA Crypto wrappers
* for the CryptoCell 310 AES APIs.
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include "psa/crypto.h"
#include "vendor/nrf52840.h"
#include "ssi_aes.h"
#include "sns_silib.h"
#include "psa_error.h"
#include "cryptocell_310_util.h"
#define ENABLE_DEBUG 0
#include "debug.h"
#define CC310_MAX_AES_INPUT_BLOCK (0xFFF0)
psa_status_t cryptocell_310_common_aes_setup(SaSiAesUserContext_t *ctx,
SaSiAesEncryptMode_t direction,
SaSiAesOperationMode_t mode,
SaSiAesPaddingType_t padding,
const uint8_t *iv,
const uint8_t *key_buffer,
size_t key_size)
{
SaSiAesUserKeyData_t key;
SaSiStatus ret = SaSi_AesInit(ctx, direction, mode, padding);
if (ret != SASI_OK) {
DEBUG("SaSi_AesInit failed with %s\n", cryptocell310_status_to_humanly_readable(ret));
return SaSi_to_psa_error(ret);
}
key.keySize = key_size;
key.pKey = (uint8_t *)key_buffer;
ret = SaSi_AesSetKey(ctx, SASI_AES_USER_KEY, &key, sizeof(key));
if (ret != SASI_OK) {
DEBUG("SaSi_AesSetKey failed with %s\n", cryptocell310_status_to_humanly_readable(ret));
return SaSi_to_psa_error(ret);
}
ret = SaSi_AesSetIv(ctx, (uint8_t *)iv);
if (ret != SASI_OK) {
DEBUG("SaSi_AesSetIv failed with %s\n", cryptocell310_status_to_humanly_readable(ret));
return SaSi_to_psa_error(ret);
}
return PSA_SUCCESS;
}
psa_status_t cryptocell_310_common_aes_encrypt_decrypt(SaSiAesUserContext_t *ctx,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
SaSiStatus ret = 0;
size_t offset = 0;
size_t size;
size_t length = input_length;
*output_length = output_size;
do {
if (length > CC310_MAX_AES_INPUT_BLOCK) {
size = CC310_MAX_AES_INPUT_BLOCK;
length -= CC310_MAX_AES_INPUT_BLOCK;
}
else {
size = length;
length = 0;
}
cryptocell_310_enable();
ret = SaSi_AesBlock(ctx, (uint8_t *)(input + offset), size, output + offset);
cryptocell_310_disable();
if (ret != SASI_OK) {
DEBUG("SaSi_AesBlock failed with %s\n", cryptocell310_status_to_humanly_readable(ret));
return SaSi_to_psa_error(ret);
}
offset += size;
} while ((length > 0) && (ret == SASI_OK));
cryptocell_310_enable();
ret = SaSi_AesFinish(ctx, length, (uint8_t *)(input + offset), input_length, output,
output_length);
cryptocell_310_disable();
if (ret != SASI_OK) {
DEBUG("SaSi_AesFinish failed with %s\n", cryptocell310_status_to_humanly_readable(ret));
return SaSi_to_psa_error(ret);
}
return PSA_SUCCESS;
}

View File

@ -0,0 +1,143 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pkg_driver_cryptocell_310
* @{
*
* @brief Common ECC functions used by all PSA Crypto wrappers
* for the CryptoCell 310 ECC APIs.
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include "psa_error.h"
#include "psa_cryptocell_310_ecc_common.h"
#include "cryptocell_310_util.h"
#define ENABLE_DEBUG 0
#include "debug.h"
extern CRYS_RND_State_t *rndState_ptr;
CRYS_ECPKI_Domain_t *pDomain;
SaSiRndGenerateVectWorkFunc_t rndGenerateVectFunc;
psa_status_t cryptocell_310_common_ecc_generate_key_pair(uint8_t *priv_key_buffer,
uint8_t *pub_key_buffer,
uint32_t *priv_key_buffer_length,
uint32_t *pub_key_buffer_length,
CRYS_ECPKI_DomainID_t domain)
{
CRYS_ECPKI_UserPrivKey_t priv_key;
CRYS_ECPKI_UserPublKey_t pub_key;
CRYS_ECPKI_KG_FipsContext_t FipsBuff;
CRYS_ECPKI_KG_TempData_t TempECCKGBuff;
CRYSError_t ret;
rndGenerateVectFunc = CRYS_RND_GenerateVector;
pDomain = (CRYS_ECPKI_Domain_t *)CRYS_ECPKI_GetEcDomain(domain);
cryptocell_310_enable();
ret = CRYS_ECPKI_GenKeyPair(rndState_ptr, rndGenerateVectFunc, pDomain, &priv_key, &pub_key,
&TempECCKGBuff, &FipsBuff);
cryptocell_310_disable();
if (ret != CRYS_OK) {
DEBUG("CRYS_ECPKI_GenKeyPair failed with %s\n", cryptocell310_status_to_humanly_readable(ret));
return CRYS_to_psa_error(ret);
}
ret = CRYS_ECPKI_ExportPrivKey(&priv_key, priv_key_buffer, priv_key_buffer_length);
if (ret != CRYS_OK) {
DEBUG("CRYS_ECPKI_ExportPrivKey failed with %s\n", cryptocell310_status_to_humanly_readable(ret));
return CRYS_to_psa_error(ret);
}
ret = CRYS_ECPKI_ExportPublKey(&pub_key, CRYS_EC_PointUncompressed, pub_key_buffer,
pub_key_buffer_length);
if (ret != CRYS_OK) {
DEBUG("CRYS_ECPKI_ExportPubKey failed with %s\n", cryptocell310_status_to_humanly_readable(ret));
return CRYS_to_psa_error(ret);
}
return PSA_SUCCESS;
}
psa_status_t cryptocell_310_common_ecc_sign_hash(const uint8_t *priv_key,
uint32_t priv_key_size,
const uint8_t *hash,
size_t hash_length,
uint8_t *signature,
size_t *signature_length,
CRYS_ECPKI_HASH_OpMode_t hash_mode,
CRYS_ECPKI_DomainID_t domain)
{
CRYS_ECDSA_SignUserContext_t SignUserContext;
CRYS_ECPKI_UserPrivKey_t user_priv_key;
CRYSError_t ret = 0;
rndGenerateVectFunc = CRYS_RND_GenerateVector;
pDomain = (CRYS_ECPKI_Domain_t *)CRYS_ECPKI_GetEcDomain(domain);
ret = CRYS_ECPKI_BuildPrivKey(pDomain, priv_key, priv_key_size, &user_priv_key);
if (ret != CRYS_OK) {
DEBUG("CRYS_ECPKI_BuildPrivKey failed with %s\n", cryptocell310_status_to_humanly_readable(ret));
return CRYS_to_psa_error(ret);
}
cryptocell_310_enable();
ret = CRYS_ECDSA_Sign(rndState_ptr, rndGenerateVectFunc,
&SignUserContext, &user_priv_key, hash_mode, (uint8_t *)hash, hash_length,
signature, (uint32_t *)signature_length);
cryptocell_310_disable();
if (ret != CRYS_OK) {
DEBUG("CRYS_ECDSA_Sign failed with %s\n", cryptocell310_status_to_humanly_readable(ret));
return CRYS_to_psa_error(ret);
}
return PSA_SUCCESS;
}
psa_status_t cryptocell_310_common_ecc_verify_hash(const uint8_t *pub_key,
size_t pub_key_size,
const uint8_t *hash,
size_t hash_length,
const uint8_t *signature,
size_t signature_length,
CRYS_ECPKI_HASH_OpMode_t hash_mode,
CRYS_ECPKI_DomainID_t domain)
{
CRYS_ECDSA_VerifyUserContext_t VerifyUserContext;
CRYS_ECPKI_UserPublKey_t user_pub_key;
CRYSError_t ret = 0;
pDomain = (CRYS_ECPKI_Domain_t *)CRYS_ECPKI_GetEcDomain(domain);
/**
* For more security, use CRYS_ECPKI_BuildPublKeyPartlyCheck or
* CRYS_ECPKI_BuildPublKeyFullCheck -> Those take longer and use more memory space
* */
ret = CRYS_ECPKI_BuildPublKey(pDomain, (uint8_t *)pub_key, pub_key_size, &user_pub_key);
if (ret != CRYS_OK) {
DEBUG("CRYS_ECPKI_BuildPublKey failed with %s\n", cryptocell310_status_to_humanly_readable(ret));
return CRYS_to_psa_error(ret);
}
cryptocell_310_enable();
ret = CRYS_ECDSA_Verify(&VerifyUserContext, &user_pub_key, hash_mode, (uint8_t *)signature,
signature_length, (uint8_t *)hash, hash_length);
cryptocell_310_disable();
if (ret != CRYS_OK) {
DEBUG("CRYS_ECDSA_Verify failed with %s\n", cryptocell310_status_to_humanly_readable(ret));
return CRYS_to_psa_error(ret);
}
return PSA_SUCCESS;
}

View File

@ -0,0 +1,76 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pkg_driver_cryptocell_310
* @{
*
* @file
* @brief Glue code translating between PSA Crypto and the CryptoCell 310 ECC P192 APIs
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include "psa_cryptocell_310_ecc_common.h"
psa_status_t psa_generate_ecc_p192r1_key_pair(const psa_key_attributes_t *attributes,
uint8_t *priv_key_buffer,
uint8_t *pub_key_buffer,
size_t *priv_key_buffer_length,
size_t *pub_key_buffer_length)
{
*priv_key_buffer_length = PSA_BITS_TO_BYTES(attributes->bits);
*pub_key_buffer_length = PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(attributes->type, attributes->bits);
return cryptocell_310_common_ecc_generate_key_pair(priv_key_buffer, pub_key_buffer,
(uint32_t *)priv_key_buffer_length,
(uint32_t *)pub_key_buffer_length,
CRYS_ECPKI_DomainID_secp192r1);
}
psa_status_t psa_ecc_p192r1_sign_hash( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const uint8_t *key_buffer,
size_t key_buffer_size,
const uint8_t *hash,
size_t hash_length,
uint8_t *signature,
size_t signature_size,
size_t *signature_length)
{
CRYS_ECPKI_HASH_OpMode_t hash_mode = MAP_PSA_HASH_TO_CRYS_HASH(PSA_ALG_GET_HASH(alg));
(void)signature_size;
(void)key_buffer_size;
return cryptocell_310_common_ecc_sign_hash(key_buffer,
PSA_BITS_TO_BYTES(attributes->bits),
hash, hash_length, signature,
signature_length, hash_mode,
CRYS_ECPKI_DomainID_secp192r1);
}
psa_status_t psa_ecc_p192r1_verify_hash(const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const uint8_t *key_buffer,
size_t key_buffer_size,
const uint8_t *hash,
size_t hash_length,
const uint8_t *signature,
size_t signature_length)
{
CRYS_ECPKI_HASH_OpMode_t hash_mode = MAP_PSA_HASH_TO_CRYS_HASH(PSA_ALG_GET_HASH(alg));
(void)attributes;
return cryptocell_310_common_ecc_verify_hash(key_buffer, key_buffer_size,
hash, hash_length, signature,
signature_length, hash_mode,
CRYS_ECPKI_DomainID_secp192r1);
}

View File

@ -0,0 +1,74 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pkg_driver_cryptocell_310
* @{
*
* @file
* @brief Glue code translating between PSA Crypto and the CryptoCell 310 ECC P256 APIs
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include "psa_cryptocell_310_ecc_common.h"
psa_status_t psa_generate_ecc_p256r1_key_pair( const psa_key_attributes_t *attributes,
uint8_t *priv_key_buffer,
uint8_t *pub_key_buffer,
size_t *priv_key_buffer_length,
size_t *pub_key_buffer_length)
{
*priv_key_buffer_length = PSA_BITS_TO_BYTES(attributes->bits);
*pub_key_buffer_length = PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(attributes->type, attributes->bits);
return cryptocell_310_common_ecc_generate_key_pair(priv_key_buffer, pub_key_buffer,
(uint32_t *)priv_key_buffer_length,
(uint32_t *)pub_key_buffer_length,
CRYS_ECPKI_DomainID_secp256r1);
}
psa_status_t psa_ecc_p256r1_sign_hash( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const uint8_t *key_buffer,
size_t key_buffer_size,
const uint8_t *hash,
size_t hash_length,
uint8_t *signature,
size_t signature_size,
size_t *signature_length)
{
(void)key_buffer_size;
CRYS_ECPKI_HASH_OpMode_t hash_mode = MAP_PSA_HASH_TO_CRYS_HASH(PSA_ALG_GET_HASH(alg));
*signature_length = signature_size;
return cryptocell_310_common_ecc_sign_hash(key_buffer,
PSA_BITS_TO_BYTES(attributes->bits),
hash, hash_length, signature,
signature_length, hash_mode,
CRYS_ECPKI_DomainID_secp256r1);
}
psa_status_t psa_ecc_p256r1_verify_hash(const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const uint8_t *key_buffer,
size_t key_buffer_size,
const uint8_t *hash,
size_t hash_length,
const uint8_t *signature,
size_t signature_length)
{
CRYS_ECPKI_HASH_OpMode_t hash_mode = MAP_PSA_HASH_TO_CRYS_HASH(PSA_ALG_GET_HASH(alg));
(void)attributes;
return cryptocell_310_common_ecc_verify_hash(key_buffer, key_buffer_size,
hash, hash_length, signature,
signature_length, hash_mode,
CRYS_ECPKI_DomainID_secp256r1);
}

View File

@ -0,0 +1,413 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pkg_driver_cryptocell_310
* @{
*
* @file
* @brief Glue code translating between PSA Crypto and the CryptoCell 310 driver APIs
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include "psa_error.h"
psa_status_t CRYS_to_psa_error(CRYSError_t error)
{
switch (error) {
case CRYS_HASH_ILLEGAL_OPERATION_MODE_ERROR:
case CRYS_HASH_IS_NOT_SUPPORTED:
return PSA_ERROR_NOT_SUPPORTED;
case CRYS_HASH_USER_CONTEXT_CORRUPTED_ERROR:
return PSA_ERROR_CORRUPTION_DETECTED;
case CRYS_ECDSA_SIGN_USER_CONTEXT_VALIDATION_TAG_ERROR:
case CRYS_ECDSA_SIGN_USER_PRIV_KEY_VALIDATION_TAG_ERROR:
case CRYS_ECDSA_VERIFY_USER_CONTEXT_VALIDATION_TAG_ERROR:
case CRYS_ECDSA_VERIFY_SIGNER_PUBL_KEY_VALIDATION_TAG_ERROR:
case CRYS_ECDSA_VERIFY_INVALID_SIGNATURE_IN_PTR_ERROR:
case CRYS_ECDSA_SIGN_INVALID_MESSAGE_DATA_IN_PTR_ERROR:
case CRYS_ECDSA_SIGN_INVALID_MESSAGE_DATA_IN_SIZE_ERROR:
case CRYS_ECDSA_VERIFY_INVALID_DOMAIN_ID_ERROR:
case CRYS_ECDSA_VERIFY_INVALID_USER_CONTEXT_PTR_ERROR:
case CRYS_ECDSA_VERIFY_INVALID_SIGNER_PUBL_KEY_PTR_ERROR:
case CRYS_ECDSA_VERIFY_ILLEGAL_HASH_OP_MODE_ERROR:
case CRYS_HASH_DATA_IN_POINTER_INVALID_ERROR:
case CRYS_ECDSA_VERIFY_INVALID_SIGNATURE_SIZE_ERROR:
case CRYS_ECDSA_VERIFY_INVALID_MESSAGE_DATA_IN_PTR_ERROR:
case CRYS_ECDSA_VERIFY_INVALID_MESSAGE_DATA_IN_SIZE_ERROR:
case CRYS_ECDSA_SIGN_INVALID_EPHEMERAL_KEY_PTR_ERROR:
case CRYS_ECDSA_SIGN_INVALID_RND_CONTEXT_PTR_ERROR:
case CRYS_ECDSA_SIGN_INVALID_RND_FUNCTION_PTR_ERROR:
case CRYS_ECDSA_SIGN_INVALID_DOMAIN_ID_ERROR:
case CRYS_ECDSA_SIGN_INVALID_USER_CONTEXT_PTR_ERROR:
case CRYS_ECDSA_SIGN_INVALID_USER_PRIV_KEY_PTR_ERROR:
case CRYS_ECDSA_SIGN_ILLEGAL_HASH_OP_MODE_ERROR:
case CRYS_ECDSA_SIGN_INVALID_SIGNATURE_OUT_PTR_ERROR:
case CRYS_ECDSA_SIGN_INVALID_SIGNATURE_OUT_SIZE_PTR_ERROR:
case CRYS_ECDSA_SIGN_INVALID_SIGNATURE_OUT_SIZE_ERROR:
case CRYS_ECC_ILLEGAL_PARAMS_ACCORDING_TO_PRIV_ERROR:
case CRYS_ECC_ILLEGAL_HASH_MODE_ERROR:
case CRYS_ECPKI_ILLEGAL_DOMAIN_ID_ERROR:
case CRYS_ECPKI_DOMAIN_PTR_ERROR:
case CRYS_ECPKI_RND_CONTEXT_PTR_ERROR:
case CRYS_ECPKI_BUILD_KEY_INVALID_COMPRESSION_MODE_ERROR:
case CRYS_ECPKI_BUILD_KEY_ILLEGAL_DOMAIN_ID_ERROR:
case CRYS_ECPKI_BUILD_KEY_INVALID_PRIV_KEY_IN_PTR_ERROR:
case CRYS_ECPKI_BUILD_KEY_INVALID_USER_PRIV_KEY_PTR_ERROR:
case CRYS_ECPKI_BUILD_KEY_INVALID_PRIV_KEY_SIZE_ERROR:
case CRYS_ECPKI_BUILD_KEY_INVALID_PRIV_KEY_DATA_ERROR:
case CRYS_ECPKI_BUILD_KEY_INVALID_PUBL_KEY_IN_PTR_ERROR:
case CRYS_ECPKI_BUILD_KEY_INVALID_USER_PUBL_KEY_PTR_ERROR:
case CRYS_ECPKI_BUILD_KEY_INVALID_PUBL_KEY_SIZE_ERROR:
case CRYS_ECPKI_BUILD_KEY_INVALID_PUBL_KEY_DATA_ERROR:
case CRYS_ECPKI_BUILD_KEY_INVALID_CHECK_MODE_ERROR:
case CRYS_ECPKI_BUILD_KEY_INVALID_TEMP_BUFF_PTR_ERROR:
case CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_USER_PUBL_KEY_PTR_ERROR:
case CRYS_ECPKI_EXPORT_PUBL_KEY_ILLEGAL_COMPRESSION_MODE_ERROR:
case CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_EXTERN_PUBL_KEY_PTR_ERROR:
case CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_PUBL_KEY_SIZE_PTR_ERROR:
case CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_PUBL_KEY_SIZE_ERROR:
case CRYS_ECPKI_EXPORT_PUBL_KEY_ILLEGAL_DOMAIN_ID_ERROR:
case CRYS_ECPKI_EXPORT_PUBL_KEY_ILLEGAL_VALIDATION_TAG_ERROR:
case CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_PUBL_KEY_DATA_ERROR:
case CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_USER_PRIV_KEY_PTR_ERROR:
case CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_EXTERN_PRIV_KEY_PTR_ERROR:
case CRYS_ECPKI_EXPORT_PRIV_KEY_ILLEGAL_VALIDATION_TAG_ERROR:
case CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_PRIV_KEY_SIZE_PTR_ERROR:
case CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_PRIV_KEY_SIZE_ERROR:
case CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_PRIV_KEY_DATA_ERROR:
case CRYS_ECPKI_BUILD_DOMAIN_ID_IS_NOT_VALID_ERROR:
case CRYS_ECPKI_BUILD_DOMAIN_DOMAIN_PTR_ERROR:
case CRYS_ECPKI_BUILD_DOMAIN_EC_PARAMETR_PTR_ERROR:
case CRYS_ECPKI_BUILD_DOMAIN_EC_PARAMETR_SIZE_ERROR:
case CRYS_ECPKI_BUILD_DOMAIN_COFACTOR_PARAMS_ERROR:
case CRYS_ECPKI_BUILD_DOMAIN_SECURITY_STRENGTH_ERROR:
case CRYS_ECPKI_BUILD_SCA_RESIST_ILLEGAL_MODE_ERROR:
case CRYS_ECDH_SVDP_DH_INVALID_PARTNER_PUBL_KEY_PTR_ERROR:
case CRYS_ECDH_SVDP_DH_PARTNER_PUBL_KEY_VALID_TAG_ERROR:
case CRYS_ECDH_SVDP_DH_INVALID_USER_PRIV_KEY_PTR_ERROR:
case CRYS_ECDH_SVDP_DH_USER_PRIV_KEY_VALID_TAG_ERROR:
case CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_PTR_ERROR:
case CRYS_ECDH_SVDP_DH_INVALID_TEMP_DATA_PTR_ERROR:
case CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_SIZE_PTR_ERROR:
case CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_SIZE_ERROR:
case CRYS_ECDH_SVDP_DH_ILLEGAL_DOMAIN_ID_ERROR:
case CRYS_ECPKI_GEN_KEY_INVALID_PRIVATE_KEY_PTR_ERROR:
case CRYS_ECPKI_GEN_KEY_INVALID_PUBLIC_KEY_PTR_ERROR:
case CRYS_ECPKI_GEN_KEY_INVALID_TEMP_DATA_PTR_ERROR:
case CRYS_ECPKI_INVALID_RND_FUNC_PTR_ERROR:
case CRYS_ECPKI_INVALID_RND_CTX_PTR_ERROR:
case CRYS_ECPKI_INVALID_DOMAIN_ID_ERROR:
case CRYS_ECPKI_INVALID_PRIV_KEY_TAG_ERROR:
case CRYS_ECPKI_INVALID_PUBL_KEY_TAG_ERROR:
case CRYS_ECPKI_INVALID_DATA_IN_PASSED_STRUCT_ERROR:
case CRYS_HASH_DATA_SIZE_ILLEGAL:
case CRYS_HASH_INVALID_RESULT_BUFFER_POINTER_ERROR:
case CRYS_HASH_ILLEGAL_PARAMS_ERROR:
case CRYS_HASH_INVALID_USER_CONTEXT_POINTER_ERROR:
case CRYS_HASH_LAST_BLOCK_ALREADY_PROCESSED_ERROR:
case CRYS_HASH_CTX_SIZES_ERROR:
return PSA_ERROR_INVALID_ARGUMENT;
default:
return PSA_ERROR_GENERIC_ERROR;
}
}
psa_status_t SaSi_to_psa_error(SaSiStatus error)
{
switch (error) {
case SASI_AES_INVALID_USER_CONTEXT_POINTER_ERROR:
case SASI_AES_INVALID_IV_OR_TWEAK_PTR_ERROR:
case SASI_AES_ILLEGAL_OPERATION_MODE_ERROR:
case SASI_AES_ILLEGAL_KEY_SIZE_ERROR:
case SASI_AES_INVALID_KEY_POINTER_ERROR:
case SASI_AES_INVALID_ENCRYPT_MODE_ERROR:
case SASI_AES_DATA_IN_POINTER_INVALID_ERROR:
case SASI_AES_DATA_OUT_POINTER_INVALID_ERROR:
case SASI_AES_DATA_IN_SIZE_ILLEGAL:
case SASI_AES_DATA_OUT_DATA_IN_OVERLAP_ERROR:
case SASI_AES_DATA_OUT_SIZE_POINTER_INVALID_ERROR:
case SASI_AES_CTX_SIZES_ERROR:
case SASI_AES_ILLEGAL_PARAMS_ERROR:
case SASI_AES_CTR_ILLEGAL_BLOCK_OFFSET_ERROR:
case SASI_AES_CTR_ILLEGAL_COUNTER_ERROR:
return PSA_ERROR_INVALID_ARGUMENT;
case SASI_AES_DATA_IN_BUFFER_SIZE_ERROR:
case SASI_AES_DATA_OUT_BUFFER_SIZE_ERROR:
return PSA_ERROR_BUFFER_TOO_SMALL;
case SASI_AES_ILLEGAL_PADDING_TYPE_ERROR:
case SASI_AES_INCORRECT_PADDING_ERROR:
return PSA_ERROR_INVALID_PADDING;
case SASI_AES_CORRUPTED_OUTPUT_ERROR:
case SASI_AES_USER_CONTEXT_CORRUPTED_ERROR:
return PSA_ERROR_CORRUPTION_DETECTED;
case SASI_AES_DECRYPTION_NOT_ALLOWED_ON_THIS_MODE:
case SASI_AES_ADDITIONAL_BLOCK_NOT_PERMITTED_ERROR:
return PSA_ERROR_NOT_PERMITTED;
case SASI_AES_KEY_TYPE_NOT_SUPPORTED_ERROR:
case SASI_AES_IS_NOT_SUPPORTED:
return PSA_ERROR_NOT_SUPPORTED;
case SASI_OUT_OF_RESOURCE_ERROR:
return PSA_ERROR_INSUFFICIENT_MEMORY;
default:
return PSA_ERROR_GENERIC_ERROR;
}
}
const char *cryptocell310_status_to_humanly_readable(uint32_t status)
{
switch(status) {
case CRYS_ECDH_SVDP_DH_NOT_CONCENT_PUBL_AND_PRIV_DOMAIN_ID_ERROR:
return "CRYS_ECDH_SVDP_DH_NOT_CONCENT_PUBL_AND_PRIV_DOMAIN_ID_ERROR";
case CRYS_ECDSA_SIGN_INVALID_IS_EPHEMER_KEY_INTERNAL_ERROR:
return "CRYS_ECDSA_SIGN_INVALID_IS_EPHEMER_KEY_INTERNAL_ERROR";
case CRYS_ECDSA_SIGN_SIGNING_ERROR:
return "CRYS_ECDSA_SIGN_SIGNING_ERROR";
case CRYS_ECDSA_VERIFY_INCONSISTENT_VERIFY_ERROR:
return "CRYS_ECDSA_VERIFY_INCONSISTENT_VERIFY_ERROR";
case CRYS_ECPKI_PKI_INTERNAL_ERROR:
return "CRYS_ECPKI_PKI_INTERNAL_ERROR";
case CRYS_HASH_ILLEGAL_OPERATION_MODE_ERROR:
return "CRYS_HASH_ILLEGAL_OPERATION_MODE_ERROR";
case CRYS_HASH_IS_NOT_SUPPORTED:
return "CRYS_HASH_IS_NOT_SUPPORTED";
case CRYS_HASH_USER_CONTEXT_CORRUPTED_ERROR:
return "CRYS_HASH_USER_CONTEXT_CORRUPTED_ERROR";
case CRYS_ECDSA_SIGN_USER_CONTEXT_VALIDATION_TAG_ERROR:
return "CRYS_ECDSA_SIGN_USER_CONTEXT_VALIDATION_TAG_ERROR";
case CRYS_ECDSA_SIGN_USER_PRIV_KEY_VALIDATION_TAG_ERROR:
return "CRYS_ECDSA_SIGN_USER_PRIV_KEY_VALIDATION_TAG_ERROR";
case CRYS_ECDSA_VERIFY_USER_CONTEXT_VALIDATION_TAG_ERROR:
return "CRYS_ECDSA_VERIFY_USER_CONTEXT_VALIDATION_TAG_ERROR";
case CRYS_ECDSA_VERIFY_SIGNER_PUBL_KEY_VALIDATION_TAG_ERROR:
return "CRYS_ECDSA_VERIFY_SIGNER_PUBL_KEY_VALIDATION_TAG_ERROR";
case CRYS_ECDSA_VERIFY_INVALID_SIGNATURE_IN_PTR_ERROR:
return "CRYS_ECDSA_VERIFY_INVALID_SIGNATURE_IN_PTR_ERROR";
case CRYS_ECDSA_SIGN_INVALID_MESSAGE_DATA_IN_PTR_ERROR:
return "CRYS_ECDSA_SIGN_INVALID_MESSAGE_DATA_IN_PTR_ERROR";
case CRYS_ECDSA_SIGN_INVALID_MESSAGE_DATA_IN_SIZE_ERROR:
return "CRYS_ECDSA_SIGN_INVALID_MESSAGE_DATA_IN_SIZE_ERROR";
case CRYS_ECDSA_VERIFY_INVALID_DOMAIN_ID_ERROR:
return "CRYS_ECDSA_VERIFY_INVALID_DOMAIN_ID_ERROR";
case CRYS_ECDSA_VERIFY_INVALID_USER_CONTEXT_PTR_ERROR:
return "CRYS_ECDSA_VERIFY_INVALID_USER_CONTEXT_PTR_ERROR";
case CRYS_ECDSA_VERIFY_INVALID_SIGNER_PUBL_KEY_PTR_ERROR:
return "CRYS_ECDSA_VERIFY_INVALID_SIGNER_PUBL_KEY_PTR_ERROR";
case CRYS_ECDSA_VERIFY_ILLEGAL_HASH_OP_MODE_ERROR:
return "CRYS_ECDSA_VERIFY_ILLEGAL_HASH_OP_MODE_ERROR";
case CRYS_HASH_DATA_IN_POINTER_INVALID_ERROR:
return "CRYS_HASH_DATA_IN_POINTER_INVALID_ERROR";
case CRYS_ECDSA_VERIFY_INVALID_SIGNATURE_SIZE_ERROR:
return "CRYS_ECDSA_VERIFY_INVALID_SIGNATURE_SIZE_ERROR";
case CRYS_ECDSA_VERIFY_INVALID_MESSAGE_DATA_IN_PTR_ERROR:
return "CRYS_ECDSA_VERIFY_INVALID_MESSAGE_DATA_IN_PTR_ERROR";
case CRYS_ECDSA_VERIFY_INVALID_MESSAGE_DATA_IN_SIZE_ERROR:
return "CRYS_ECDSA_VERIFY_INVALID_MESSAGE_DATA_IN_SIZE_ERROR";
case CRYS_ECDSA_SIGN_INVALID_EPHEMERAL_KEY_PTR_ERROR:
return "CRYS_ECDSA_SIGN_INVALID_EPHEMERAL_KEY_PTR_ERROR";
case CRYS_ECDSA_SIGN_INVALID_RND_CONTEXT_PTR_ERROR:
return "CRYS_ECDSA_SIGN_INVALID_RND_CONTEXT_PTR_ERROR";
case CRYS_ECDSA_SIGN_INVALID_RND_FUNCTION_PTR_ERROR:
return "CRYS_ECDSA_SIGN_INVALID_RND_FUNCTION_PTR_ERROR";
case CRYS_ECDSA_SIGN_INVALID_DOMAIN_ID_ERROR:
return "CRYS_ECDSA_SIGN_INVALID_DOMAIN_ID_ERROR";
case CRYS_ECDSA_SIGN_INVALID_USER_CONTEXT_PTR_ERROR:
return "CRYS_ECDSA_SIGN_INVALID_USER_CONTEXT_PTR_ERROR";
case CRYS_ECDSA_SIGN_INVALID_USER_PRIV_KEY_PTR_ERROR:
return "CRYS_ECDSA_SIGN_INVALID_USER_PRIV_KEY_PTR_ERROR";
case CRYS_ECDSA_SIGN_ILLEGAL_HASH_OP_MODE_ERROR:
return "CRYS_ECDSA_SIGN_ILLEGAL_HASH_OP_MODE_ERROR";
case CRYS_ECDSA_SIGN_INVALID_SIGNATURE_OUT_PTR_ERROR:
return "CRYS_ECDSA_SIGN_INVALID_SIGNATURE_OUT_PTR_ERROR";
case CRYS_ECDSA_SIGN_INVALID_SIGNATURE_OUT_SIZE_PTR_ERROR:
return "CRYS_ECDSA_SIGN_INVALID_SIGNATURE_OUT_SIZE_PTR_ERROR";
case CRYS_ECDSA_SIGN_INVALID_SIGNATURE_OUT_SIZE_ERROR:
return "CRYS_ECDSA_SIGN_INVALID_SIGNATURE_OUT_SIZE_ERROR";
case CRYS_ECC_ILLEGAL_PARAMS_ACCORDING_TO_PRIV_ERROR:
return "CRYS_ECC_ILLEGAL_PARAMS_ACCORDING_TO_PRIV_ERROR";
case CRYS_ECC_ILLEGAL_HASH_MODE_ERROR:
return "CRYS_ECC_ILLEGAL_HASH_MODE_ERROR";
case CRYS_ECPKI_ILLEGAL_DOMAIN_ID_ERROR:
return "CRYS_ECPKI_ILLEGAL_DOMAIN_ID_ERROR";
case CRYS_ECPKI_DOMAIN_PTR_ERROR:
return "CRYS_ECPKI_DOMAIN_PTR_ERROR";
case CRYS_ECPKI_RND_CONTEXT_PTR_ERROR:
return "CRYS_ECPKI_RND_CONTEXT_PTR_ERROR";
case CRYS_ECPKI_BUILD_KEY_INVALID_COMPRESSION_MODE_ERROR:
return "CRYS_ECPKI_BUILD_KEY_INVALID_COMPRESSION_MODE_ERROR";
case CRYS_ECPKI_BUILD_KEY_ILLEGAL_DOMAIN_ID_ERROR:
return "CRYS_ECPKI_BUILD_KEY_ILLEGAL_DOMAIN_ID_ERROR";
case CRYS_ECPKI_BUILD_KEY_INVALID_PRIV_KEY_IN_PTR_ERROR:
return "CRYS_ECPKI_BUILD_KEY_INVALID_PRIV_KEY_IN_PTR_ERROR";
case CRYS_ECPKI_BUILD_KEY_INVALID_USER_PRIV_KEY_PTR_ERROR:
return "CRYS_ECPKI_BUILD_KEY_INVALID_USER_PRIV_KEY_PTR_ERROR";
case CRYS_ECPKI_BUILD_KEY_INVALID_PRIV_KEY_SIZE_ERROR:
return "CRYS_ECPKI_BUILD_KEY_INVALID_PRIV_KEY_SIZE_ERROR";
case CRYS_ECPKI_BUILD_KEY_INVALID_PRIV_KEY_DATA_ERROR:
return "CRYS_ECPKI_BUILD_KEY_INVALID_PRIV_KEY_DATA_ERROR";
case CRYS_ECPKI_BUILD_KEY_INVALID_PUBL_KEY_IN_PTR_ERROR:
return "CRYS_ECPKI_BUILD_KEY_INVALID_PUBL_KEY_IN_PTR_ERROR";
case CRYS_ECPKI_BUILD_KEY_INVALID_USER_PUBL_KEY_PTR_ERROR:
return "CRYS_ECPKI_BUILD_KEY_INVALID_USER_PUBL_KEY_PTR_ERROR";
case CRYS_ECPKI_BUILD_KEY_INVALID_PUBL_KEY_SIZE_ERROR:
return "CRYS_ECPKI_BUILD_KEY_INVALID_PUBL_KEY_SIZE_ERROR";
case CRYS_ECPKI_BUILD_KEY_INVALID_PUBL_KEY_DATA_ERROR:
return "CRYS_ECPKI_BUILD_KEY_INVALID_PUBL_KEY_DATA_ERROR";
case CRYS_ECPKI_BUILD_KEY_INVALID_CHECK_MODE_ERROR:
return "CRYS_ECPKI_BUILD_KEY_INVALID_CHECK_MODE_ERROR";
case CRYS_ECPKI_BUILD_KEY_INVALID_TEMP_BUFF_PTR_ERROR:
return "CRYS_ECPKI_BUILD_KEY_INVALID_TEMP_BUFF_PTR_ERROR";
case CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_USER_PUBL_KEY_PTR_ERROR:
return "CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_USER_PUBL_KEY_PTR_ERROR";
case CRYS_ECPKI_EXPORT_PUBL_KEY_ILLEGAL_COMPRESSION_MODE_ERROR:
return "CRYS_ECPKI_EXPORT_PUBL_KEY_ILLEGAL_COMPRESSION_MODE_ERROR";
case CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_EXTERN_PUBL_KEY_PTR_ERROR:
return "CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_EXTERN_PUBL_KEY_PTR_ERROR";
case CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_PUBL_KEY_SIZE_PTR_ERROR:
return "CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_PUBL_KEY_SIZE_PTR_ERROR";
case CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_PUBL_KEY_SIZE_ERROR:
return "CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_PUBL_KEY_SIZE_ERROR";
case CRYS_ECPKI_EXPORT_PUBL_KEY_ILLEGAL_DOMAIN_ID_ERROR:
return "CRYS_ECPKI_EXPORT_PUBL_KEY_ILLEGAL_DOMAIN_ID_ERROR";
case CRYS_ECPKI_EXPORT_PUBL_KEY_ILLEGAL_VALIDATION_TAG_ERROR:
return "CRYS_ECPKI_EXPORT_PUBL_KEY_ILLEGAL_VALIDATION_TAG_ERROR";
case CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_PUBL_KEY_DATA_ERROR:
return "CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_PUBL_KEY_DATA_ERROR";
case CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_USER_PRIV_KEY_PTR_ERROR:
return "CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_USER_PRIV_KEY_PTR_ERROR";
case CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_EXTERN_PRIV_KEY_PTR_ERROR:
return "CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_EXTERN_PRIV_KEY_PTR_ERROR";
case CRYS_ECPKI_EXPORT_PRIV_KEY_ILLEGAL_VALIDATION_TAG_ERROR:
return "CRYS_ECPKI_EXPORT_PRIV_KEY_ILLEGAL_VALIDATION_TAG_ERROR";
case CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_PRIV_KEY_SIZE_PTR_ERROR:
return "CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_PRIV_KEY_SIZE_PTR_ERROR";
case CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_PRIV_KEY_SIZE_ERROR:
return "CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_PRIV_KEY_SIZE_ERROR";
case CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_PRIV_KEY_DATA_ERROR:
return "CRYS_ECPKI_EXPORT_PRIV_KEY_INVALID_PRIV_KEY_DATA_ERROR";
case CRYS_ECPKI_BUILD_DOMAIN_ID_IS_NOT_VALID_ERROR:
return "CRYS_ECPKI_BUILD_DOMAIN_ID_IS_NOT_VALID_ERROR";
case CRYS_ECPKI_BUILD_DOMAIN_DOMAIN_PTR_ERROR:
return "CRYS_ECPKI_BUILD_DOMAIN_DOMAIN_PTR_ERROR";
case CRYS_ECPKI_BUILD_DOMAIN_EC_PARAMETR_PTR_ERROR:
return "CRYS_ECPKI_BUILD_DOMAIN_EC_PARAMETR_PTR_ERROR";
case CRYS_ECPKI_BUILD_DOMAIN_EC_PARAMETR_SIZE_ERROR:
return "CRYS_ECPKI_BUILD_DOMAIN_EC_PARAMETR_SIZE_ERROR";
case CRYS_ECPKI_BUILD_DOMAIN_COFACTOR_PARAMS_ERROR:
return "CRYS_ECPKI_BUILD_DOMAIN_COFACTOR_PARAMS_ERROR";
case CRYS_ECPKI_BUILD_DOMAIN_SECURITY_STRENGTH_ERROR:
return "CRYS_ECPKI_BUILD_DOMAIN_SECURITY_STRENGTH_ERROR";
case CRYS_ECPKI_BUILD_SCA_RESIST_ILLEGAL_MODE_ERROR:
return "CRYS_ECPKI_BUILD_SCA_RESIST_ILLEGAL_MODE_ERROR";
case CRYS_ECDH_SVDP_DH_INVALID_PARTNER_PUBL_KEY_PTR_ERROR:
return "CRYS_ECDH_SVDP_DH_INVALID_PARTNER_PUBL_KEY_PTR_ERROR";
case CRYS_ECDH_SVDP_DH_PARTNER_PUBL_KEY_VALID_TAG_ERROR:
return "CRYS_ECDH_SVDP_DH_PARTNER_PUBL_KEY_VALID_TAG_ERROR";
case CRYS_ECDH_SVDP_DH_INVALID_USER_PRIV_KEY_PTR_ERROR:
return "CRYS_ECDH_SVDP_DH_INVALID_USER_PRIV_KEY_PTR_ERROR";
case CRYS_ECDH_SVDP_DH_USER_PRIV_KEY_VALID_TAG_ERROR:
return "CRYS_ECDH_SVDP_DH_USER_PRIV_KEY_VALID_TAG_ERROR";
case CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_PTR_ERROR:
return "CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_PTR_ERROR";
case CRYS_ECDH_SVDP_DH_INVALID_TEMP_DATA_PTR_ERROR:
return "CRYS_ECDH_SVDP_DH_INVALID_TEMP_DATA_PTR_ERROR";
case CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_SIZE_PTR_ERROR:
return "CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_SIZE_PTR_ERROR";
case CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_SIZE_ERROR:
return "CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_SIZE_ERROR";
case CRYS_ECDH_SVDP_DH_ILLEGAL_DOMAIN_ID_ERROR:
return "CRYS_ECDH_SVDP_DH_ILLEGAL_DOMAIN_ID_ERROR";
case CRYS_ECPKI_GEN_KEY_INVALID_PRIVATE_KEY_PTR_ERROR:
return "CRYS_ECPKI_GEN_KEY_INVALID_PRIVATE_KEY_PTR_ERROR";
case CRYS_ECPKI_GEN_KEY_INVALID_PUBLIC_KEY_PTR_ERROR:
return "CRYS_ECPKI_GEN_KEY_INVALID_PUBLIC_KEY_PTR_ERROR";
case CRYS_ECPKI_GEN_KEY_INVALID_TEMP_DATA_PTR_ERROR:
return "CRYS_ECPKI_GEN_KEY_INVALID_TEMP_DATA_PTR_ERROR";
case CRYS_ECPKI_INVALID_RND_FUNC_PTR_ERROR:
return "CRYS_ECPKI_INVALID_RND_FUNC_PTR_ERROR";
case CRYS_ECPKI_INVALID_RND_CTX_PTR_ERROR:
return "CRYS_ECPKI_INVALID_RND_CTX_PTR_ERROR";
case CRYS_ECPKI_INVALID_DOMAIN_ID_ERROR:
return "CRYS_ECPKI_INVALID_DOMAIN_ID_ERROR";
case CRYS_ECPKI_INVALID_PRIV_KEY_TAG_ERROR:
return "CRYS_ECPKI_INVALID_PRIV_KEY_TAG_ERROR";
case CRYS_ECPKI_INVALID_PUBL_KEY_TAG_ERROR:
return "CRYS_ECPKI_INVALID_PUBL_KEY_TAG_ERROR";
case CRYS_ECPKI_INVALID_DATA_IN_PASSED_STRUCT_ERROR:
return "CRYS_ECPKI_INVALID_DATA_IN_PASSED_STRUCT_ERROR";
case CRYS_HASH_DATA_SIZE_ILLEGAL:
return "CRYS_HASH_DATA_SIZE_ILLEGAL";
case CRYS_HASH_INVALID_RESULT_BUFFER_POINTER_ERROR:
return "CRYS_HASH_INVALID_RESULT_BUFFER_POINTER_ERROR";
case CRYS_HASH_ILLEGAL_PARAMS_ERROR:
return "CRYS_HASH_ILLEGAL_PARAMS_ERROR";
case CRYS_HASH_INVALID_USER_CONTEXT_POINTER_ERROR:
return "CRYS_HASH_INVALID_USER_CONTEXT_POINTER_ERROR";
case CRYS_HASH_LAST_BLOCK_ALREADY_PROCESSED_ERROR:
return "CRYS_HASH_LAST_BLOCK_ALREADY_PROCESSED_ERROR";
case CRYS_HASH_CTX_SIZES_ERROR:
return "CRYS_HASH_CTX_SIZES_ERROR";
case SASI_AES_INVALID_USER_CONTEXT_POINTER_ERROR:
return "SASI_AES_INVALID_USER_CONTEXT_POINTER_ERROR";
case SASI_AES_INVALID_IV_OR_TWEAK_PTR_ERROR:
return "SASI_AES_INVALID_IV_OR_TWEAK_PTR_ERROR";
case SASI_AES_ILLEGAL_OPERATION_MODE_ERROR:
return "SASI_AES_ILLEGAL_OPERATION_MODE_ERROR";
case SASI_AES_ILLEGAL_KEY_SIZE_ERROR:
return "SASI_AES_ILLEGAL_KEY_SIZE_ERROR";
case SASI_AES_INVALID_KEY_POINTER_ERROR:
return "SASI_AES_INVALID_KEY_POINTER_ERROR";
case SASI_AES_INVALID_ENCRYPT_MODE_ERROR:
return "SASI_AES_INVALID_ENCRYPT_MODE_ERROR";
case SASI_AES_DATA_IN_POINTER_INVALID_ERROR:
return "SASI_AES_DATA_IN_POINTER_INVALID_ERROR";
case SASI_AES_DATA_OUT_POINTER_INVALID_ERROR:
return "SASI_AES_DATA_OUT_POINTER_INVALID_ERROR";
case SASI_AES_DATA_IN_SIZE_ILLEGAL:
return "SASI_AES_DATA_IN_SIZE_ILLEGAL";
case SASI_AES_DATA_OUT_DATA_IN_OVERLAP_ERROR:
return "SASI_AES_DATA_OUT_DATA_IN_OVERLAP_ERROR";
case SASI_AES_DATA_OUT_SIZE_POINTER_INVALID_ERROR:
return "SASI_AES_DATA_OUT_SIZE_POINTER_INVALID_ERROR";
case SASI_AES_CTX_SIZES_ERROR:
return "SASI_AES_CTX_SIZES_ERROR";
case SASI_AES_ILLEGAL_PARAMS_ERROR:
return "SASI_AES_ILLEGAL_PARAMS_ERROR";
case SASI_AES_CTR_ILLEGAL_BLOCK_OFFSET_ERROR:
return "SASI_AES_CTR_ILLEGAL_BLOCK_OFFSET_ERROR";
case SASI_AES_CTR_ILLEGAL_COUNTER_ERROR:
return "SASI_AES_CTR_ILLEGAL_COUNTER_ERROR";
case SASI_AES_DATA_IN_BUFFER_SIZE_ERROR:
return "SASI_AES_DATA_IN_BUFFER_SIZE_ERROR";
case SASI_AES_DATA_OUT_BUFFER_SIZE_ERROR:
return "SASI_AES_DATA_OUT_BUFFER_SIZE_ERROR";
case SASI_AES_ILLEGAL_PADDING_TYPE_ERROR:
return "SASI_AES_ILLEGAL_PADDING_TYPE_ERROR";
case SASI_AES_INCORRECT_PADDING_ERROR:
return "SASI_AES_INCORRECT_PADDING_ERROR";
case SASI_AES_CORRUPTED_OUTPUT_ERROR:
return "SASI_AES_CORRUPTED_OUTPUT_ERROR";
case SASI_AES_USER_CONTEXT_CORRUPTED_ERROR:
return "SASI_AES_USER_CONTEXT_CORRUPTED_ERROR";
case SASI_AES_DECRYPTION_NOT_ALLOWED_ON_THIS_MODE:
return "SASI_AES_DECRYPTION_NOT_ALLOWED_ON_THIS_MODE";
case SASI_AES_ADDITIONAL_BLOCK_NOT_PERMITTED_ERROR:
return "SASI_AES_ADDITIONAL_BLOCK_NOT_PERMITTED_ERROR";
case SASI_AES_KEY_TYPE_NOT_SUPPORTED_ERROR:
return "SASI_AES_KEY_TYPE_NOT_SUPPORTED_ERROR";
case SASI_AES_IS_NOT_SUPPORTED:
return "SASI_AES_IS_NOT_SUPPORTED";
case SASI_OUT_OF_RESOURCE_ERROR:
return "SASI_OUT_OF_RESOURCE_ERROR";
default:
return "Error value not recognized";
}
}

View File

@ -0,0 +1,87 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pkg_driver_cryptocell_310
* @{
*
* @brief Common hash functions used by all PSA Crypto wrappers
* for the CryptoCell 310 hash APIs.
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include "psa/crypto.h"
#include "psa_error.h"
#include "cryptocell_310_util.h"
#include "crys_hash.h"
#define ENABLE_DEBUG 0
#include "debug.h"
#define CC310_MAX_HASH_INPUT_BLOCK (0xFFF0)
psa_status_t cryptocell_310_common_hash_setup(CRYS_HASHUserContext_t *ctx,
CRYS_HASH_OperationMode_t mode)
{
CRYSError_t ret = CRYS_HASH_Init(ctx, mode);
if (ret != CRYS_OK) {
DEBUG("CRYS_HASH_Init failed with %s\n", cryptocell310_status_to_humanly_readable(ret));
return CRYS_to_psa_error(ret);
}
return PSA_SUCCESS;
}
psa_status_t cryptocell_310_common_hash_update(CRYS_HASHUserContext_t *ctx,
const uint8_t *input,
size_t input_length)
{
CRYSError_t ret = 0;
size_t offset = 0;
size_t size;
do {
if (input_length > CC310_MAX_HASH_INPUT_BLOCK) {
size = CC310_MAX_HASH_INPUT_BLOCK;
input_length -= CC310_MAX_HASH_INPUT_BLOCK;
}
else {
size = input_length;
input_length = 0;
}
cryptocell_310_enable();
ret = CRYS_HASH_Update(ctx, (uint8_t *)(input + offset), size);
cryptocell_310_disable();
offset += size;
} while ((input_length > 0) && (ret == CRYS_OK));
if (ret != CRYS_OK) {
DEBUG("CRYS_HASH_Update failed with %s\n", cryptocell310_status_to_humanly_readable(ret));
return CRYS_to_psa_error(ret);
}
return PSA_SUCCESS;
}
psa_status_t cryptocell_310_common_hash_finish(CRYS_HASHUserContext_t *ctx, uint8_t *hash, size_t hash_size,
size_t *hash_length)
{
cryptocell_310_enable();
CRYSError_t ret = CRYS_HASH_Finish(ctx, (uint32_t *)hash);
cryptocell_310_disable();
if (ret != CRYS_OK) {
DEBUG("CRYS_HASH_Finish failed with %s\n", cryptocell310_status_to_humanly_readable(ret));
return CRYS_to_psa_error(ret);
}
*hash_length = hash_size;
return PSA_SUCCESS;
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pkg_driver_cryptocell_310
* @{
*
* @brief Glue code translating between PSA Crypto and the CryptoCell 310 SHA1 APIs
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include <stdio.h>
#include "kernel_defines.h"
#include "psa_periph_hashes_ctx.h"
#include "psa_cryptocell_310_hashes_common.h"
psa_status_t psa_hashes_sha1_setup(psa_hashes_sha1_ctx_t *ctx)
{
return cryptocell_310_common_hash_setup((CRYS_HASHUserContext_t *)ctx, CRYS_HASH_SHA1_mode);
}
psa_status_t psa_hashes_sha1_update(psa_hashes_sha1_ctx_t *ctx,
const uint8_t *input,
size_t input_length)
{
return cryptocell_310_common_hash_update((CRYS_HASHUserContext_t *)ctx, input, input_length);
}
psa_status_t psa_hashes_sha1_finish(psa_hashes_sha1_ctx_t *ctx,
uint8_t *hash,
size_t hash_size,
size_t *hash_length)
{
return cryptocell_310_common_hash_finish((CRYS_HASHUserContext_t *)ctx, hash, hash_size, hash_length);
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pkg_driver_cryptocell_310
* @{
*
* @brief Glue code translating between PSA Crypto and the CryptoCell 310 SHA224 APIs
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include <stdio.h>
#include "kernel_defines.h"
#include "psa_periph_hashes_ctx.h"
#include "psa_cryptocell_310_hashes_common.h"
psa_status_t psa_hashes_sha224_setup(psa_hashes_sha224_ctx_t *ctx)
{
return cryptocell_310_common_hash_setup((CRYS_HASHUserContext_t *)ctx, CRYS_HASH_SHA224_mode);
}
psa_status_t psa_hashes_sha224_update(psa_hashes_sha224_ctx_t *ctx,
const uint8_t *input,
size_t input_length)
{
return cryptocell_310_common_hash_update((CRYS_HASHUserContext_t *)ctx, input, input_length);
}
psa_status_t psa_hashes_sha224_finish(psa_hashes_sha224_ctx_t *ctx,
uint8_t *hash,
size_t hash_size,
size_t *hash_length)
{
return cryptocell_310_common_hash_finish((CRYS_HASHUserContext_t *)ctx, hash, hash_size, hash_length);
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pkg_driver_cryptocell_310
* @{
*
* @brief Glue code translating between PSA Crypto and the CryptoCell 310 SHA256 APIs
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include "kernel_defines.h"
#include "psa_periph_hashes_ctx.h"
#include "psa_cryptocell_310_hashes_common.h"
psa_status_t psa_hashes_sha256_setup(psa_hashes_sha256_ctx_t *ctx)
{
return cryptocell_310_common_hash_setup((CRYS_HASHUserContext_t *)ctx, CRYS_HASH_SHA256_mode);
}
psa_status_t psa_hashes_sha256_update(psa_hashes_sha256_ctx_t *ctx,
const uint8_t *input,
size_t input_length)
{
return cryptocell_310_common_hash_update((CRYS_HASHUserContext_t *)ctx, input, input_length);
}
psa_status_t psa_hashes_sha256_finish(psa_hashes_sha256_ctx_t *ctx,
uint8_t *hash,
size_t hash_size,
size_t *hash_length)
{
return cryptocell_310_common_hash_finish((CRYS_HASHUserContext_t *)ctx, hash, hash_size, hash_length);
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pkg_driver_cryptocell_310
* @{
*
* @brief Glue code translating between PSA Crypto and the CryptoCell 310 SHA512 APIs
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include <stdio.h>
#include "kernel_defines.h"
#include "psa_periph_hashes_ctx.h"
#include "psa_cryptocell_310_hashes_common.h"
psa_status_t psa_hashes_sha512_setup(psa_hashes_sha512_ctx_t *ctx)
{
return cryptocell_310_common_hash_setup((CRYS_HASHUserContext_t *)ctx, CRYS_HASH_SHA512_mode);
}
psa_status_t psa_hashes_sha512_update(psa_hashes_sha512_ctx_t *ctx,
const uint8_t *input,
size_t input_length)
{
return cryptocell_310_common_hash_update((CRYS_HASHUserContext_t *)ctx, input, input_length);
}
psa_status_t psa_hashes_sha512_finish( psa_hashes_sha512_ctx_t *ctx,
uint8_t *hash,
size_t hash_size,
size_t *hash_length)
{
return cryptocell_310_common_hash_finish((CRYS_HASHUserContext_t *)ctx, hash, hash_size, hash_length);
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pkg_driver_cryptocell_310
* @{
*
* @brief Glue code translating between PSA Crypto and the CryptoCell 310 driver APIs
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include "kernel_defines.h"
#include "psa/crypto.h"
#include "psa_error.h"
#include "crys_hmac.h"
#include "crys_hmac_error.h"
#define ENABLE_DEBUG 0
#include "debug.h"
psa_status_t psa_mac_compute_hmac_sha256(const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
const uint8_t *input,
size_t input_length,
uint8_t *mac,
size_t mac_size,
size_t *mac_length)
{
CRYSError_t ret;
size_t required_mac_length =
PSA_MAC_LENGTH(attributes->type, attributes->bits, PSA_ALG_SHA_256);
if (mac_size < required_mac_length) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
ret = CRYS_HMAC(CRYS_HASH_SHA256_mode, (uint8_t *)key_buffer, key_buffer_size, (uint8_t *)input,
input_length, (uint32_t *)mac);
if (ret != CRYS_OK) {
DEBUG("CRYS_HMAC failed with %s\n", cryptocell310_status_to_humanly_readable(ret));
return CRYS_to_psa_error(ret);
}
*mac_length = required_mac_length;
(void)mac_size;
return PSA_SUCCESS;
}

View File

@ -15,3 +15,5 @@ config PACKAGE_MICRO-ECC
https://github.com/kmackay/micro-ecc and adds `hwrng_read` as
the default RNG function if it is available on the target
platform.
rsource "psa_uecc/Kconfig"

View File

@ -6,3 +6,10 @@ CFLAGS += -Wno-unused-variable
# llvm fails to allocate registers for inline assembly :/
TOOLCHAINS_BLACKLIST += llvm
ifneq (,$(filter psa_uecc_%, $(USEMODULE)))
PSEUDOMODULES += psa_uecc_p192
PSEUDOMODULES += psa_uecc_p256
DIRS += $(RIOTPKG)/micro-ecc/psa_uecc
INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include
endif

View File

@ -0,0 +1,19 @@
# Copyright (c) 2021 HAW Hamburg
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
config MODULE_PSA_UECC_P192
bool
depends on MODULE_PSA_CRYPTO
select MODULE_PSA_UECC
config MODULE_PSA_UECC_P256
bool
depends on MODULE_PSA_CRYPTO
select MODULE_PSA_UECC
config MODULE_PSA_UECC
bool

View File

@ -0,0 +1,4 @@
BASE_MODULE := psa_uecc
SUBMODULES := 1
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,84 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto pkg_micro-ecc
* @{
*
* @brief Glue code translating between PSA Crypto and the Micro-ECC APIs
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include "psa/crypto.h"
#include "uECC.h"
psa_status_t psa_generate_ecc_p192r1_key_pair( const psa_key_attributes_t *attributes,
uint8_t *priv_key_buffer, uint8_t *pub_key_buffer,
size_t *priv_key_buffer_length,
size_t *pub_key_buffer_length)
{
int ret = 0;
*priv_key_buffer_length = PSA_BITS_TO_BYTES(attributes->bits);
*pub_key_buffer_length = PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(attributes->type, attributes->bits);
const struct uECC_Curve_t *curve = uECC_secp192r1();
ret = uECC_make_key(pub_key_buffer, priv_key_buffer, curve);
if (!ret) {
return PSA_ERROR_GENERIC_ERROR;
}
return PSA_SUCCESS;
}
psa_status_t psa_ecc_p192r1_sign_hash( const psa_key_attributes_t *attributes,
psa_algorithm_t alg, const uint8_t *key_buffer,
size_t key_buffer_size, const uint8_t *hash,
size_t hash_length, uint8_t *signature,
size_t signature_size, size_t *signature_length)
{
int ret = 0;
const struct uECC_Curve_t *curve = uECC_secp192r1();
ret = uECC_sign(key_buffer, hash, hash_length, signature, curve);
if (!ret) {
return PSA_ERROR_GENERIC_ERROR;
}
*signature_length = signature_size;
(void)alg;
(void)attributes;
(void)key_buffer_size;
return PSA_SUCCESS;
}
psa_status_t psa_ecc_p192r1_verify_hash(const psa_key_attributes_t *attributes,
psa_algorithm_t alg, const uint8_t *key_buffer,
size_t key_buffer_size, const uint8_t *hash,
size_t hash_length, const uint8_t *signature,
size_t signature_length)
{
int ret = 0;
const struct uECC_Curve_t *curve = uECC_secp192r1();
ret = uECC_verify(key_buffer, hash, hash_length, signature, curve);
if (!ret) {
return PSA_ERROR_GENERIC_ERROR;
}
(void)alg;
(void)attributes;
(void)key_buffer_size;
(void)signature_length;
return PSA_SUCCESS;
}

View File

@ -0,0 +1,84 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto pkg_micro-ecc
* @{
*
* @brief Glue code translating between PSA Crypto and the Micro-ECC APIs
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include "psa/crypto.h"
#include "uECC.h"
psa_status_t psa_generate_ecc_p256r1_key_pair( const psa_key_attributes_t *attributes,
uint8_t *priv_key_buffer, uint8_t *pub_key_buffer,
size_t *priv_key_buffer_length,
size_t *pub_key_buffer_length)
{
int ret = 0;
*priv_key_buffer_length = PSA_BITS_TO_BYTES(attributes->bits);
*pub_key_buffer_length = PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(attributes->type, attributes->bits);
const struct uECC_Curve_t *curve = uECC_secp256r1();
ret = uECC_make_key(pub_key_buffer, priv_key_buffer, curve);
if (!ret) {
return PSA_ERROR_GENERIC_ERROR;
}
return PSA_SUCCESS;
}
psa_status_t psa_ecc_p256r1_sign_hash( const psa_key_attributes_t *attributes,
psa_algorithm_t alg, const uint8_t *key_buffer,
size_t key_buffer_size, const uint8_t *hash,
size_t hash_length, uint8_t *signature,
size_t signature_size, size_t *signature_length)
{
int ret = 0;
const struct uECC_Curve_t *curve = uECC_secp256r1();
ret = uECC_sign(key_buffer, hash, hash_length, signature, curve);
if (!ret) {
return PSA_ERROR_GENERIC_ERROR;
}
*signature_length = signature_size;
(void)alg;
(void)attributes;
(void)key_buffer_size;
return PSA_SUCCESS;
}
psa_status_t psa_ecc_p256r1_verify_hash(const psa_key_attributes_t *attributes,
psa_algorithm_t alg, const uint8_t *key_buffer,
size_t key_buffer_size, const uint8_t *hash,
size_t hash_length, const uint8_t *signature,
size_t signature_length)
{
int ret = 0;
const struct uECC_Curve_t *curve = uECC_secp256r1();
ret = uECC_verify(key_buffer, hash, hash_length, signature, curve);
if (!ret) {
return PSA_ERROR_GENERIC_ERROR;
}
(void)alg;
(void)attributes;
(void)key_buffer_size;
(void)signature_length;
return PSA_SUCCESS;
}

View File

@ -93,6 +93,7 @@ rsource "posix/Kconfig"
rsource "preprocessor/Kconfig"
rsource "progress_bar/Kconfig"
rsource "ps/Kconfig"
rsource "psa_crypto/Kconfig"
rsource "random/Kconfig"
rsource "rtc_utils/Kconfig"
rsource "rust_riotmodules/Kconfig"

View File

@ -173,6 +173,9 @@ endif
ifneq (,$(filter posix_sleep,$(USEMODULE)))
DIRS += posix/sleep
endif
ifneq (,$(filter psa_crypto,$(USEMODULE)))
DIRS += psa_crypto
endif
ifneq (,$(filter pthread,$(USEMODULE)))
DIRS += posix/pthread
endif

View File

@ -686,6 +686,14 @@ ifneq (,$(filter fido2_ctap%,$(USEMODULE)))
USEMODULE += fido2
endif
ifneq (,$(filter psa_crypto,$(USEMODULE)))
include $(RIOTBASE)/sys/psa_crypto/Makefile.dep
endif
ifneq (,$(filter psa_riot_cipher_aes_%,$(USEMODULE)))
USEMODULE += psa_riot_cipher_aes_common
endif
ifneq (,$(filter rust_riotmodules,$(USEMODULE)))
include $(RIOTBASE)/sys/rust_riotmodules/Makefile.dep
endif

View File

@ -163,6 +163,10 @@ ifneq (,$(filter prng,$(USEMODULE)))
include $(RIOTBASE)/sys/random/Makefile.include
endif
ifneq (,$(filter psa_crypto,$(USEMODULE)))
include $(RIOTBASE)/sys/psa_crypto/Makefile.include
endif
ifneq (,$(filter test_utils_netdev_eth_minimal,$(USEMODULE)))
CFLAGS += -DCONFIG_NETDEV_REGISTER_SIGNAL
endif

View File

@ -278,11 +278,14 @@ AUTO_INIT(auto_init_mbedtls,
AUTO_INIT_PRIO_MOD_MBEDTLS);
#endif
#if IS_USED(MODULE_AUTO_INIT_SECURITY)
#if IS_USED(MODULE_CRYPTOAUTHLIB)
extern void auto_init_atca(void);
AUTO_INIT(auto_init_atca,
AUTO_INIT_PRIO_MOD_CRYPTOAUTHLIB);
extern void auto_init_security(void);
AUTO_INIT(auto_init_security,
AUTO_INIT_PRIO_MOD_SECURITY);
#endif
#if IS_USED(MODULE_DRIVER_CRYPTOCELL_310)
extern void driver_cryptocell_310_setup(void);
AUTO_INIT(driver_cryptocell_310_setup,
AUTO_INIT_PRIO_MOD_DRIVER_CRYPTOCELL_310);
#endif
#if IS_USED(MODULE_TEST_UTILS_INTERACTIVE_SYNC) && !IS_USED(MODULE_SHELL)
extern void test_utils_interactive_sync(void);

View File

@ -317,11 +317,11 @@ extern "C" {
*/
#define AUTO_INIT_PRIO_MOD_MBEDTLS 1440
#endif
#ifndef AUTO_INIT_PRIO_MOD_CRYPTOAUTHLIB
#ifndef AUTO_INIT_PRIO_MOD_SECURITY
/**
* @brief CryptoAuthLib priority
*/
#define AUTO_INIT_PRIO_MOD_CRYPTOAUTHLIB 1450
#define AUTO_INIT_PRIO_MOD_SECURITY 1450
#endif
#ifndef AUTO_INIT_PRIO_MOD_TEST_UTILS_INTERACTIVE_SYNC
/**
@ -389,6 +389,12 @@ extern "C" {
*/
#define AUTO_INIT_PRIO_MOD_GNRC_IPV6_STATIC_ADDR 1560
#endif
#ifndef AUTO_INIT_PRIO_MOD_DRIVER_CRYPTOCELL_310
/**
* @brief CryptoCell Driver Priority
*/
#define AUTO_INIT_PRIO_MOD_DRIVER_CRYPTOCELL_310 1570
#endif
#ifdef __cplusplus
}

View File

@ -19,18 +19,62 @@
#include "log.h"
#include "atca.h"
#include "atca_params.h"
#include "kernel_defines.h"
#define ENABLE_DEBUG 0
#include "debug.h"
#define ATCA_NUMOF (ARRAY_SIZE(atca_params))
#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A)
#include "psa/crypto.h"
#include "psa_crypto_se_management.h"
extern psa_drv_se_t atca_methods;
psa_se_config_t atca_config_list[] = { ATCA_CONFIG_LIST };
#endif
ATCADevice atca_devs_ptr[ATCA_NUMOF];
static struct atca_device atca_devs[ATCA_NUMOF];
#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A)
void auto_init_atca(void)
{
DEBUG("[auto_init_atca] Number of secure elements: %d\n", ATCA_NUMOF);
for (unsigned i = 0; i < ATCA_NUMOF; i++) {
if (atcab_init((ATCAIfaceCfg *)&atca_params[i]) != ATCA_SUCCESS) {
LOG_ERROR("[auto_init_atca] error initializing cryptoauth device #%u\n", i);
int status = initATCADevice((ATCAIfaceCfg *)&atca_params[i].cfg, (ATCADevice)&atca_devs[i]);
if (status != ATCA_SUCCESS) {
LOG_ERROR("[auto_init_atca] error initializing cryptoauth device #%u, status: %d\n",
i, status);
continue;
}
atca_devs_ptr[i] = &atca_devs[i];
DEBUG("[auto_init_atca] Registering Driver with address: %x and location: %lx\n", atca_params[i].cfg.atcai2c.address, atca_params[i].atca_loc);
status = psa_register_secure_element(atca_params[i].atca_loc,
&atca_methods,
&atca_config_list[i],
&atca_devs[i]);
if (status != PSA_SUCCESS) {
LOG_ERROR(
"[auto_init_atca] PSA Crypto error registering cryptoauth PSA driver\
for device #%u, status: %s\n", i, psa_status_to_humanly_readable(status));
continue;
}
}
}
#else
void auto_init_atca(void)
{
DEBUG("[auto_init_atca] Number of secure elements: %d\n", ATCA_NUMOF);
for (unsigned i = 0; i < ATCA_NUMOF; i++) {
int status = initATCADevice((ATCAIfaceCfg *)&atca_params[i], (ATCADevice)&atca_devs[i]);
if (status != ATCA_SUCCESS) {
LOG_ERROR("[auto_init_atca] error initializing cryptoauth device #%u, status: %d\n",
i, status);
continue;
}
atca_devs_ptr[i] = &atca_devs[i];
}
}
#endif

View File

@ -0,0 +1,30 @@
/*
* Copyright (C) 2023 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_auto_init
* @{
* @file
* @brief Initializes security modules
*
* @author Bennet Blischke <bennet.blischke@haw-hamburg.de>
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg,de>
* @}
*/
#define ENABLE_DEBUG 0
#include "debug.h"
void auto_init_security(void)
{
#if IS_USED(MODULE_CRYPTOAUTHLIB)
extern void auto_init_atca(void);
DEBUG("auto_init_security: atca\n");
auto_init_atca();
#endif
}

View File

@ -33,6 +33,7 @@ config MODULE_CRYPTO_AES_UNROLL
endmenu # Crypto AES options
rsource "psa_riot_cipher/Kconfig"
rsource "modes/Kconfig"
endif # Crypto

View File

@ -4,4 +4,8 @@ endif
CFLAGS += -DRIOT_CHACHA_PRNG_DEFAULT="$(RIOT_CHACHA_PRNG_DEFAULT)"
ifneq (,$(filter psa_riot_cipher_%,$(USEMODULE)))
DIRS += psa_riot_cipher
endif
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,38 @@
# Copyright (c) 2021 HAW Hamburg
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
config MODULE_PSA_RIOT_CIPHER_AES_128_ECB
bool
depends on MODULE_PSA_CRYPTO
select MODULE_CRYPTO_AES_128
select MODULE_PSA_RIOT_CIPHER
config MODULE_PSA_RIOT_CIPHER_AES_128_CBC
bool
depends on MODULE_PSA_CRYPTO
select MODULE_CRYPTO_AES_128
select MODULE_PSA_RIOT_CIPHER
config MODULE_PSA_RIOT_CIPHER_AES_192_CBC
bool
depends on MODULE_PSA_CRYPTO
select MODULE_CRYPTO_AES_192
select MODULE_PSA_RIOT_CIPHER
config MODULE_PSA_RIOT_CIPHER_AES_256_CBC
bool
depends on MODULE_PSA_CRYPTO
select MODULE_CRYPTO_AES_192
select MODULE_PSA_RIOT_CIPHER
config MODULE_PSA_RIOT_CIPHER
bool
select MODULE_PSA_RIOT_CIPHER_AES_COMMON
select MODULE_CIPHER_MODES
config MODULE_PSA_RIOT_CIPHER_AES_COMMON
bool

View File

@ -0,0 +1,4 @@
BASE_MODULE := psa_riot_cipher
SUBMODULES := 1
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,91 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @{
*
* @file
* @brief Glue code translating between PSA Crypto and the RIOT Cipher module
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include "psa/crypto.h"
#include "crypto/modes/cbc.h"
#include "aes_common.h"
#define ENABLE_DEBUG 0
#include "debug.h"
psa_status_t psa_cipher_cbc_aes_128_encrypt(const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
DEBUG("RIOT AES 128 Cipher");
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_cipher_operation_t operation = psa_cipher_operation_init();
size_t iv_length = 0;
size_t required_output_buf_size = PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_AES,
PSA_ALG_CBC_NO_PADDING, input_length);
if (output_size < required_output_buf_size) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
operation.iv_required = 1;
operation.default_iv_length = PSA_CIPHER_IV_LENGTH(attributes->type, alg);
*output_length = 0;
status = psa_cipher_generate_iv(&operation, output, operation.default_iv_length, &iv_length);
if (status != PSA_SUCCESS) {
return status;
}
return cbc_aes_common_encrypt_decrypt(&operation.backend_ctx.cipher_ctx.aes_128, key_buffer,
key_buffer_size, output, input, input_length,
output + iv_length, output_length, PSA_CRYPTO_DRIVER_ENCRYPT);
}
psa_status_t psa_cipher_cbc_aes_128_decrypt(const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
DEBUG("RIOT AES 128 Cipher");
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_cipher_operation_t operation = psa_cipher_operation_init();
size_t required_output_buf_size = PSA_CIPHER_DECRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_AES,
PSA_ALG_CBC_NO_PADDING, input_length);
if (output_size < required_output_buf_size) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
operation.iv_required = 1;
operation.default_iv_length = PSA_CIPHER_IV_LENGTH(attributes->type, alg);
*output_length = 0;
return cbc_aes_common_encrypt_decrypt(&operation.backend_ctx.cipher_ctx.aes_128, key_buffer,
key_buffer_size, input, input + operation.default_iv_length,
input_length - operation.default_iv_length, output,
output_length, PSA_CRYPTO_DRIVER_DECRYPT);
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @{
*
* @file
* @brief Glue code translating between PSA Crypto and the RIOT Cipher module
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include "psa/crypto.h"
#include "crypto/modes/cbc.h"
#include "aes_common.h"
#define ENABLE_DEBUG 0
#include "debug.h"
psa_status_t psa_cipher_cbc_aes_256_encrypt(const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
DEBUG("RIOT AES 256 Cipher");
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_cipher_operation_t operation = psa_cipher_operation_init();
size_t iv_length = 0;
size_t required_output_buf_size = PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_AES,
PSA_ALG_CBC_NO_PADDING, input_length);
if (output_size < required_output_buf_size) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
operation.iv_required = 1;
operation.default_iv_length = PSA_CIPHER_IV_LENGTH(attributes->type, alg);
*output_length = 0;
status = psa_cipher_generate_iv(&operation, output, operation.default_iv_length, &iv_length);
if (status != PSA_SUCCESS) {
return status;
}
status = cbc_aes_common(&operation.backend_ctx.cipher_ctx.aes_256, key_buffer, key_buffer_size,
output, input, input_length, output + operation.default_iv_length,
output_length);
return status;
}

View File

@ -0,0 +1,68 @@
/*
* Copyright (C) 2022 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @{
*
* @file
* @brief Glue code translating between PSA Crypto and the RIOT Cipher module
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include "psa/crypto.h"
#include "crypto/modes/cbc.h"
#define ENABLE_DEBUG 0
#include "debug.h"
psa_status_t cipher_to_psa_error(int error)
{
switch (error) {
case CIPHER_ERR_INVALID_KEY_SIZE:
case CIPHER_ERR_INVALID_LENGTH:
case CIPHER_ERR_BAD_CONTEXT_SIZE:
return PSA_ERROR_INVALID_ARGUMENT;
default:
return PSA_ERROR_GENERIC_ERROR;
}
}
psa_status_t cbc_aes_common_encrypt_decrypt(cipher_t *ctx,
const uint8_t *key_buffer,
size_t key_buffer_size,
const uint8_t *iv,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t *output_length,
psa_encrypt_or_decrypt_t direction)
{
int ret = 0;
ret = cipher_init(ctx, CIPHER_AES, key_buffer, key_buffer_size);
if (ret != CIPHER_INIT_SUCCESS) {
return cipher_to_psa_error(ret);
}
if (direction == PSA_CRYPTO_DRIVER_ENCRYPT) {
ret = cipher_encrypt_cbc(ctx, (uint8_t *)iv, input, input_length, output);
}
else {
ret = cipher_decrypt_cbc(ctx, (uint8_t *)iv, input, input_length, output);
}
if (ret <= 0) {
return cipher_to_psa_error(ret);
}
*output_length = ret;
return PSA_SUCCESS;
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2022 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @cond
* @ingroup sys_crypto
* @{
*
* @brief Glue code translating between PSA Crypto and the RIOT Cipher module
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef AES_COMMON_H
#define AES_COMMON_H
#ifdef __cplusplus
extern "C" {
#endif
#include "psa/crypto.h"
#include "crypto/modes/cbc.h"
/**
* @brief Converts errors of the RIOT cipher module to PSA status values
*
* @param error
* @return @ref psa_status_t
*/
psa_status_t cipher_to_psa_error(int error);
/**
* @brief Common AES CBC Encrypt function
*
* @return @ref psa_status_t
*/
psa_status_t cbc_aes_common_encrypt_decrypt(cipher_t *ctx,
const uint8_t *key_buffer,
size_t key_buffer_size,
const uint8_t *iv,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t *output_length,
psa_encrypt_or_decrypt_t direction);
#ifdef __cplusplus
}
#endif
#endif /* AES_COMMON_H */
/** @} */
/** @endcond */

View File

@ -9,3 +9,5 @@ config MODULE_HASHES
bool "Hash algorithms"
depends on TEST_KCONFIG
select MODULE_CRYPTO
rsource "psa_riot_hashes/Kconfig"

View File

@ -1 +1,7 @@
MODULE := hashes
ifneq (,$(filter psa_riot_hashes_%,$(USEMODULE)))
DIRS += psa_riot_hashes
endif
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,39 @@
# Copyright (c) 2021 HAW Hamburg
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
config MODULE_PSA_RIOT_HASHES_MD5
bool
depends on MODULE_PSA_CRYPTO
select MODULE_PSA_RIOT_HASHES
select MODULE_HASHES
config MODULE_PSA_RIOT_HASHES_SHA_1
bool
depends on MODULE_PSA_CRYPTO
select MODULE_PSA_RIOT_HASHES
select MODULE_HASHES
config MODULE_PSA_RIOT_HASHES_SHA_224
bool
depends on MODULE_PSA_CRYPTO
select MODULE_PSA_RIOT_HASHES
select MODULE_HASHES
config MODULE_PSA_RIOT_HASHES_SHA_256
bool
depends on MODULE_PSA_CRYPTO
select MODULE_PSA_RIOT_HASHES
select MODULE_HASHES
config MODULE_PSA_RIOT_HASHES_HMAC_SHA256
bool
depends on MODULE_PSA_CRYPTO
select MODULE_PSA_RIOT_HASHES
select MODULE_HASHES
config MODULE_PSA_RIOT_HASHES
bool

View File

@ -0,0 +1,4 @@
BASE_MODULE := psa_riot_hashes
SUBMODULES := 1
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2022 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @{
*
* @brief Glue code translating between PSA Crypto and the RIOT Hash module
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include "psa/crypto.h"
#include "hashes/psa/riot_hashes.h"
psa_status_t psa_mac_compute_hmac_sha256(const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
const uint8_t *input,
size_t input_length,
uint8_t *mac,
size_t mac_size,
size_t *mac_length)
{
hmac_sha256(key_buffer, key_buffer_size, input, input_length, mac);
*mac_length = 32;
(void)mac_size;
(void)attributes;
return PSA_SUCCESS;
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2022 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @{
*
* @brief Glue code translating between PSA Crypto and the RIOT Hash module
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include "psa/crypto.h"
#include "hashes/psa/riot_hashes.h"
psa_status_t psa_hashes_md5_setup(psa_hashes_md5_ctx_t *ctx)
{
md5_init((md5_ctx_t *)ctx);
return PSA_SUCCESS;
}
psa_status_t psa_hashes_md5_update(psa_hashes_md5_ctx_t *ctx,
const uint8_t *input,
size_t input_length)
{
md5_update((md5_ctx_t *)ctx, input, input_length);
return PSA_SUCCESS;
}
psa_status_t psa_hashes_md5_finish(psa_hashes_md5_ctx_t *ctx,
uint8_t *hash,
size_t hash_size,
size_t *hash_length)
{
md5_final((md5_ctx_t *)ctx, hash);
(void)hash_size;
(void)hash_length;
return PSA_SUCCESS;
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2022 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @{
*
* @brief Glue code translating between PSA Crypto and the RIOT Hash module
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include "psa/crypto.h"
#include "hashes/psa/riot_hashes.h"
psa_status_t psa_hashes_sha1_setup(psa_hashes_sha1_ctx_t *ctx)
{
sha1_init((sha1_context *)ctx);
return PSA_SUCCESS;
}
psa_status_t psa_hashes_sha1_update(psa_hashes_sha1_ctx_t *ctx,
const uint8_t *input,
size_t input_length)
{
sha1_update((sha1_context *)ctx, input, input_length);
return PSA_SUCCESS;
}
psa_status_t psa_hashes_sha1_finish(psa_hashes_sha1_ctx_t *ctx,
uint8_t *hash,
size_t hash_size,
size_t *hash_length)
{
sha1_final((sha1_context *)ctx, hash);
(void)hash_size;
(void)hash_length;
return PSA_SUCCESS;
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2022 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @{
*
* @brief Glue code translating between PSA Crypto and the RIOT Hash module
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include "psa/crypto.h"
#include "hashes/psa/riot_hashes.h"
psa_status_t psa_hashes_sha224_setup(psa_hashes_sha224_ctx_t *ctx)
{
sha224_init((sha224_context_t *)ctx);
return PSA_SUCCESS;
}
psa_status_t psa_hashes_sha224_update(psa_hashes_sha224_ctx_t *ctx,
const uint8_t *input,
size_t input_length)
{
sha224_update((sha224_context_t *)ctx, input, input_length);
return PSA_SUCCESS;
}
psa_status_t psa_hashes_sha224_finish(psa_hashes_sha224_ctx_t *ctx,
uint8_t *hash,
size_t hash_size,
size_t *hash_length)
{
sha224_final((sha224_context_t *)ctx, hash);
(void)hash_size;
(void)hash_length;
return PSA_SUCCESS;
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2022 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @{
*
* @brief Glue code translating between PSA Crypto and the RIOT Hash module
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include "psa/crypto.h"
#include "hashes/psa/riot_hashes.h"
psa_status_t psa_hashes_sha256_setup(psa_hashes_sha256_ctx_t *ctx)
{
sha256_init((sha256_context_t *)ctx);
return PSA_SUCCESS;
}
psa_status_t psa_hashes_sha256_update(psa_hashes_sha256_ctx_t *ctx,
const uint8_t *input,
size_t input_length)
{
sha256_update((sha256_context_t *)ctx, input, input_length);
return PSA_SUCCESS;
}
psa_status_t psa_hashes_sha256_finish(psa_hashes_sha256_ctx_t *ctx,
uint8_t *hash,
size_t hash_size,
size_t *hash_length)
{
sha256_final((sha256_context_t *)ctx, hash);
(void)hash_size;
(void)hash_length;
return PSA_SUCCESS;
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2022 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @{
*
* @brief Contexts for the RIOT cipher module
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef CRYPTO_PSA_RIOT_CIPHERS_H
#define CRYPTO_PSA_RIOT_CIPHERS_H
#ifdef __cplusplus
extern "C" {
#endif
#include "crypto/ciphers.h"
#include "kernel_defines.h"
#if IS_USED(MODULE_PSA_RIOT_CIPHER_AES_128_CBC)
typedef cipher_t psa_cipher_aes_128_ctx_t;
#endif
#if IS_USED(MODULE_PSA_RIOT_CIPHER_AES_192_CBC)
typedef cipher_t psa_cipher_aes_192_ctx_t;
#endif
#if IS_USED(MODULE_PSA_RIOT_CIPHER_AES_256_CBC)
typedef cipher_t psa_cipher_aes_256_ctx_t;
#endif
#ifdef __cplusplus
}
#endif
#endif /* CRYPTO_PSA_RIOT_CIPHERS_H */
/** @} */

Some files were not shown because too many files have changed in this diff Show More