Adaptive AUTOSAR——Cryptography (VRTE R21-11)
Posted aFakeProgramer
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Adaptive AUTOSAR——Cryptography (VRTE R21-11)相关的知识,希望对你有一定的参考价值。
11.1 What is Cryptography?
Cryptography是自适应平台体系结构中的一个功能集群,负责为自适应应用程序提供加密功能。
作为一个功能集群,Cryptography提供了允许以可移植和灵活的方式访问加密原语(即算法)的基础设施。此外,由于有一层抽象,自适应平台的集成商可以利用加密原语的多个实现,而不需要在自适应应用程序内部进行任何代码更改。
11.1.1 Architecture
Cryptography的高层体系结构如图11.1所示。
功能分为三个领域:
- 密钥存储
- 加密算法提供程序管理
- 证书管理。
每个区域在功能上是分开的,相互作用。自适应平台API为它们之间的交互提供了便利。
11.1.1.1 密钥存储Key Storage
密钥存储负责密钥管理,包括密钥的安全存储(例如加密密钥),因此得名。
钥匙存储在钥匙槽中,每个槽可以存储一把钥匙。
在自适应应用程序可以使用密钥之前,它需要知道它存储在哪个密钥槽中。
这是通过InstanceSpecifier实现的,其工作原理如下:
Adaptive Application开发人员首先创建一个类型为CryptoKeySlotInterface的RPortPrototype,然后使用该端口原型的InstanceSpecifier来访问密钥槽。
因此,自适应应用程序从不直接引用特定的密钥槽,而是引用RPortPrototype。
因此,积分器可以在映射期间自由选择任何键槽。密钥存储概述如图11.2所示。
出于安全原因,自适应应用程序无法访问原始密钥材料,而是使用密钥句柄。这种设计确保了自适应应用程序使用的任何密钥在应用程序受损的情况下保持安全(换句话说,自适应应用程序不应该泄露密钥)。
11.1.1.2加密提供程序管理 Crypto Provider Management
加密提供程序负责实现加密原语,并使自适应应用程序能够以可移植的方式在提供程序之间切换。
加密提供程序的使用使自适应应用程序能够执行基本的加密操作(例如加密或解密)。
如图11.3所示,开发人员首先创建一个使用CryptoProviderInterface类型的RPortPrototype,然后使用该端口的InstanceSpecifier来访问所实现的功能。在部署过程中,集成商将此端口映射到可用的加密提供程序。
从自适应应用程序的角度来看,加密提供商是可交换的(假设它们实现相同的功能),集成商有责任选择正确的实现;不期望每个可用的加密提供方(即加密库)将实现相同的一组算法。
此外,当需要时间敏感的计算时,可能需要硬件加速。
因此,Adaptive Platform支持每个Adaptive应用程序使用多个加密提供方,即使不同提供方支持的实现可能有所不同。
11.1.1.3 X.509 Certificate Management
自适应平台支持国际电信联盟(ITU)的X.509标准[9]中所述的公钥证书管理。
证书将有关密钥(它所认证的公钥)的信息与有关该密钥所有者的信息绑定在一起。
这允许证书的用户检查私钥所有者的身份,以及私钥是否与公钥匹配。
证书管理负责证书存储和证书吊销列表(CRL)。
11.2 Configuration and Workflow
加密工作流程分为两个阶段:
- 应用程序设计(第12.1节)
- 集成(第11.2节)。
密钥和加密提供者的工作流程非常相似,主要区别在于元素和属性的名称和类型。
11.2.1 Application Design
此版本的RTA-VRTE入门套件不支持加密的ARXML配置。不使用端口接口,自适应应用程序使用预定义的值(见第11.2.2.1节)。
然而,Adaptive AUTOSAR规范规定必须配置至少一个加密提供程序才能执行任何加密操作。
这些要求已经反映在密码学的工作中,因此,创建这样的元素是强制性的。
需要在Machine元素下创建包含Crypto Provider对象的Crypto Module实例化,以满足Crypto Daemon。
要在编辑器中创建加密模块实例化,请右键单击Machine -->New Child --> Module Instantiation --> Crypto Module Instantiation.
Figure 11.5: Creation of Crypto Module Instantiation element
To create a Crypto Provider, right-click on the Crypto Module Instantiation -->New Child --> Crypto Provider.
Figure 11.6: Creation of Crypto Provider element
这些元素只需要创建,而不需要配置。计划在未来版本中提供完整的配置支持。
注意:配置这些元素后,应用程序将运行,但用户可能仍然会收到一个错误,即未配置CryptoKeySlots。这是因为,如前所述,还没有添加对加密的ARXML配置的支持。但是,此错误不会影响应用程序的工作。
11.2.2 Integration
在使用之前,必须将每个功能集群集成并部署到机器上。集成确保每个功能集群都得到了正确配置,并且满足了任何运行时依赖关系。
11.2.2.1 Configuration
如上文第11.2.1节所述,RTA-VRTE入门套件V3.0中的加密配置选项是有限的,尤其是所有可用的密钥槽和加密提供程序都是硬编码的。作为固定配置的一部分,有五个通用键槽可用于自适应应用程序:
- CryptoQTProcess/CryptoQTExecutable/RSCP_CryptoQTUser/customkeyslot1
- CryptoQTProcess/CryptoQTExecutable/RSCP_CryptoQTUser/customkeyslot2
- CryptoQTProcess/CryptoQTExecutable/RSCP_CryptoQTUser/customkeyslot3
- CryptoQTProcess/CryptoQTExecutable/RSCP_CryptoQTUser/customkeyslot4
- CryptoQTProcess/CryptoQTExecutable/RSCP_CryptoQTUser/customkeyslot5
在创建用于识别密钥槽的InstanceSpecifier对象时,自适应应用程序应使用上面的字符串之一,而不是第11.1.1.1节中所述的RPortPrototype的元模型标识符。
用于密钥存储的密钥槽文件由集成商准备,因此RTA-VRTE入门套件不会创建它们。
准备好的文件可以是空的——假设密钥注入发生在运行时——但一旦注入,它们就可以重新用于测试目的。集成商应在文件系统上创建以下文件:
- /opt/vrte/crypto_daemon/per/type2/customkeyslot1.bin
- /opt/vrte/crypto_daemon/per/type2/customkeyslot2.bin
- /opt/vrte/crypto_daemon/per/type2/customkeyslot3.bin
- /opt/vrte/crypto_daemon/per/type2/customkeyslot4.bin
- /opt/vrte/crypto_daemon/per/type2/customkeyslot5.bin
如果项目使用文件系统权限来保护文件不受未经授权的访问,则集成程序必须相应地配置加密。特别是,应该在执行编辑器中将正确的用户和组ID分配给代表加密的守护进程进程(有关更多详细信息,请参阅第4.5.3节)。
警告:未能为密钥存储创建文件将导致自定义密钥槽无法使用;
例如,它们将无法从自适应应用程序访问。如果Cryptographic没有访问文件系统上现有相关文件的权限,也会发生同样的情况。
RTA-VRTE入门套件V3.0.0支持单个加密提供程序。创建InstanceSpecifier对象时,自适应应用程序应使用字符串wolfssl,而不是第11.1.1.2节中所述的RPortPrototype的元模型标识符。
11.2.2.2 Command-line Arguments
为crypto_demon可执行文件配置Process元素时,集成程序应创建一个值如下的命令行参数:
-k ecucfg。
有关如何配置命令行参数的详细信息,请参阅第4.5.3节。
11.2.2.3 Cross Functional Cluster Dependencies
加密在运行时依赖于通信管理。为crypto_demon可执行文件配置Process元素时,集成程序应为Process arapipcd创建类型为RUNNING的Execution Dependency,以便加密库和加密服务守护程序可以相互通信。有关配置执行依赖项的详细信息,请参见第4.5.5节。
这些依赖关系的图形表示如图11.7所示。加密没有引入通信管理的额外配置要求,有关如何配置通信管理的详细信息,请参阅第9章。
11.2.2.4 External Dependencies
加密技术使用wolfSSL库作为加密提供程序。开源版本可以从下载https://github.com/wolfSSL/wolfssl.
RTA-VRTE入门套件V3.0.0已经通过库的4.3.0版本进行了测试。
11.2.3 Supported Algorithms
RTA-VRTE入门套件V3.0.0支持多种加密算法。使用密码学时,您需要知道要使用的算法的名称。创建加密上下文(执行加密计算的对象)时需要这样做,有关更多信息,请参阅第11.3.4节。
本节列出RTA-VRTE入门套件V3.0.0支持的算法名称。
Hash Functions : 哈希函数:
- “SHA-1”
- “SHA-224”
- “SHA-256”
- “SHA-384”
- “SHA-512”
Message Authentication Codes : 消息身份验证代码:
- “GMAC/AES-128”
- “GMAC/AES-192”
- “GMAC/AES-256”
- “CMAC/AES-128”
- “CMAC/AES-192”
- “CMAC/AES-256”
Digital Signatures : 数字签名:
- “RSASSA/PSS,SHA-256”
- “RSASSA/PSS,SHA-256,RSA-3072”
- “RSASSA/PSS,SHA-256,RSA-4096”
- “RSASSA/PKCS1-v1_5,SHA-256”
- “RSASSA/PKCS1-v1_5,SHA-256,RSA-3072”
- “RSASSA/PKCS1-v1_5,SHA-256,RSA-4096”
- “Ed25519”
- “ECDSA/SECP256R1/SHA-256”
Block Ciphers : 分组密码:
- “ECB/AES-128/PKCS7”
- “ECB/AES-192/PKCS7”
- “ECB/AES-256/PKCS7”
- “CBC/AES-128/PKCS7”
- “CBC/AES-192/PKCS7”
- “CBC/AES-256/PKCS7”
- “CTR/AES-128”
- “CTR/AES-192”
- “CTR/AES-256”
- “GCM/AES-128”
- “GCM/AES-192”
- “GCM/AES-256”
Random Number Generators : 随机数生成器:
- “RNG/GLOBAL”
Key Derivation Functions : 关键派生函数:
- “PBKDF2,SHA-1”
- “PBKDF2,SHA-256”
- “PBKDF2,MD5”
- “AES-MP”
注意:在对密钥注入的密钥进行编码的情况下,只有算法是相关的,而不是操作类型,请参见第11.3.3.1节中的密钥导入模式。
11.3 Working with Cryptography
软件开发人员。我们将首先关注加密软件包的安装,然后是软件开发的编译阶段,然后转到运行时方面。这里的重点将是密钥注入,然后是加密/解密。这一概述应该为密码学的进一步探索奠定坚实的基础。
11.3.1 Crypto Package Installation加密包安装
在开始开发使用加密的自适应应用程序之前,用户必须首先安装包含加密功能集群和wolfSSL库的加密包。
注意:Crypto软件包目前尚未作为RTA-VRTE入门套件的一部分发布,而是单独分发的。可以通过联系ETAS技术支持来请求该软件包,请参阅第24章。
要安装Crypto软件包,请将Crypto-SK_<ver_number>.tar文件放在RTA-VRTE入门套件内的桌面上,然后打开终端窗口并执行以下命令:
$cd /opt/etas/vrte/sdk
$tar -xvf ~/Desktop/Crypto-SK_<ver_number>.tar
第一个命令将当前文件夹更改为安装RTA-VRTE SDK的文件夹。第二个命令将提取并安装Crypto包。
11.3.2 Software Compilation
注意:本节中的示例假设使用基于CMake的构建系统,尽管所提供的信息应广泛适用并独立于构建系统。
编译自适应应用程序时,需要向编译器提供包含文件和链接库的位置。使用加密功能集群的自适应应用程序也将依赖于执行客户端和加密库——使用以下CMake包可以很容易地找到这些库:
find_package(exm-executionclient-lib CONFIG REQUIRED)
find_package(crypto REQUIRED)
上述命令将定位所需的包,并创建包含库和include目录信息的变量。以下命令将此信息应用于特定可执行文件的生成过程:
target_include_directories(executable_name
$EXM_EXECUTIONCLIENT_LIB_INCLUDE_DIRS
$CRYPTO_INCLUDE_DIRS ...)
target_link_libraries(executable_name
$EXM_EXECUTIONCLIENT_LIB_LIBRARIES
$CRYPTO_LIBRARIES ...)
11.3.3 Key Injection密钥注入
在使用钥匙槽内的钥匙之前,首先需要将其注入(即写入或保存)到钥匙存储器(或者更准确地说,注入到钥匙槽)。RTA-VRTE入门套件V3.0.0支持使用ImportPublicObject接口将加密密钥材料注入密钥存储槽。
AUTOSAR还支持易失性容器形式的临时密钥,这些临时密钥可以通过AllocVolatileContainer接口进行分配。临时密钥存储在RAM中,其寿命仅限于自适应应用程序的寿命,例如,它们不能存储在密钥槽中。临时密钥注入也由ImportPublicObject接口执行。
11.3.3.1 Key Import Schema 密钥导入架构
RTA-VRTE入门套件可以导入(即注入)根据提供的ASN.1架构(RTA\\verte_key_import_schema.ASN)编码的密钥。导入架构定义如下:
在架构中指定的ImportFormat类型内部。必须定义以下值:
metadataVersionNumber-一个整数,表示当前数据(即对象内部的数据)编码所依据的架构版本。
对于RTA-VRTE入门套件V3.0.0,元数据版本号应设置为0(零)。
mObjectUidQwordMs、mObjectUidQwordLs和mObjectUidVersionStamp-它们一起形成加密对象唯一标识符(COUID)。
在AUTOSAR中,COUID分为两部分:生成器Uid,由mObjectUidQwordMs.mObjectUidQ wordLs形成,以及唯一标识生成器生成(注入)的对象(密钥)的mObjectUid版本戳。
AUTOSAR要求每个密钥都有自己的COUID,对于注入的密钥,应在执行ASN.1编码时提供。在测试或早期开发阶段,建议使用简单的编号方案,例如0.1.1、0.1.2、1.3,但生产案例应使用中央密钥管理方案,该方案应提供适当的值。
请注意,在AUTOSAR中,存在一个空的COUID(Nil),它等于0.0.0,因此建议从0.1.1开始编号。
当注入非对称密钥时,预计公钥和私钥将共享相同的COUID,但它们将因mObjectType而不同。
mObjectSize—mObject的大小(以字节为单位)。当注入2048位密钥(例如RSA 2048密钥)时,mObjectSize应设置为256。
mObjectType—正在注入的键的类型。可用类型包括:
- kSymmetricKey
- kPrivateKey
- kPublicKey
- kSignature
- kSecretSeed
mAlgId-为其注入密钥的加密算法的ID。支持的加密算法ID包括:
- aes-128
- aes-192
- aes-256
- rsa-2048
- rsa-3072
- rsa-4096
- ed25519
- secp256R1
- curve25519、
mContentAllowedUsage-一个位字段,用于指定密钥的可用/支持的加密操作。
可以使用以下位值(可以通过执行逐位OR运算符来组合多个值):
- kAllowPrototypedOnly = 0x0000
- kAllowDataEncryption = 0x0001
- kAllowDataDecryption = 0x0002
- kAllowSignature = 0x0004
- kAllowVerification = 0x0008
- kAllowKeyAgreement = 0x0010
- kAllowKeyDiversify = 0x0020
- kAllowRngInit = 0x0040
- kAllowKdfMaterial = 0x0080
- kAllowKeyExporting = 0x0100
- kAllowKeyImporting = 0x0200
- kAllowExactModeOnly = 0x8000
- kAllowDerivedDataEncryption = kAllowDataEncryption «16
- kAllowDerivedDataDecryption = kAllowDataDecryption «16
- kAllowDerivedSignature = kAllowSignature « 16
- kAllowDerivedVerification = kAllowVerification « 16
- kAllowDerivedKeyDiversify = kAllowKeyDiversify « 16
- kAllowDerivedRngInit = kAllowRngInit « 16
- kAllowDerivedKdfMaterial = kAllowKdfMaterial « 16
- kAllowDerivedKeyExporting = kAllowKeyExporting « 16
- kAllowDerivedKeyImporting = kAllowKeyImporting « 16
- kAllowDerivedExactModeOnly = kAllowExactModeOnly « 16
注:“«”运算符象征着左位移位。
mContentAllowedUsage设置为kAllowPrototypedOnly的密钥不能用于任何加密操作。
只有在为以后的密钥注入保留密钥槽时,此值才有用。
mObjectEncoding-指定用于mObject的编码。
mObjectEncoding的定义值为:
- raw
- der
- pem
RTA-VRTE入门套件支持密钥注入的原始格式,不应使用其他值。
mSessionFlag-指定这是否是一个临时(即会话)密钥。如果设置为true,即这是一个会话密钥,Adaptive Application将无法将此密钥存储在密钥槽中。
RTA-VRTE入门套件中未使用此标志。
mObject—按mObjectEncoding指定的方式编码的键的值
11.3.3.2 Key Encoding
在注入密钥之前,必须先对其进行编码。
RTA-VRTE入门套件密钥导入模式如第11.3.3.1节所述,可在RTA\\verte_key_import_schema.asn文件中找到。
ASN.1标准得到广泛支持,Adaptive Application开发人员可以使用任何合适的现成工具进行密钥编码——在本节中,将使用Python库asn1tools[3]。虽然代码示例是用Python编写的,但所提供的信息应该是广泛适用的,并且与语言无关。
在本节中,将使用NIST[12]的测试矢量。特别地,作为这种特定操作模式的AES算法的CBC模式对于要加密的短数据集和长数据集(又称纯文本)都能很好地工作。CBCMMT128.rsp文件中的测试向量COUNT_0将用作我们示例的基础:
COUNT = 0
KEY = 1f8e4973953f3fb0bd6b16662e9a3c17
IV = 2fe2b333ceda8f98f4a99b40d2cd34a8
PLAINTEXT = 45cf12964fc824ab76616ae2f4bf0822
CIPHERTEXT = 0f61c4d44c5147c03c195ad7e2cc12b2
第一步是导入asn1tools模块,并根据第11.3.3.1节中描述的模式创建一个字典来存储数据:
一旦描述了密钥,就可以将其编译为ASN.1模式。在编译过程中,对模式进行解析并检查其正确性——如果成功,则返回可用于编码的对象。
# Before we can encode a key, in accordance to ASN.1 schema,
# we first need to compile mentioned schema.
# Please note that we will use the DER format for encoding our key
# (this is specified by second parameter in the function call).
# Information about DER format can be found here:
# https://en.wikipedia.org/wiki/X.690#DER_encoding
rta_vrte_key_import = asn1tools.compile_files(
’rta_vrte_key_import_schema.asn’, ’der’
)
RTA-VRTE入门套件V3.0.0仅在导入密钥时支持DER格式。
关键材料编码(在ASN.1模式中设置)与容器编码(在对对象进行编码时设置)是分开的,因此这些值可能不同。
encode方法采用两个参数:第一个参数是用于编码数据的模式中使用的类型的名称(rta_vrte_key_import_schema.asn只有一个类型——ImportFormat);第二个参数是包含关键字及其描述的字典。
# Encode a key described by AES_count_0_key dictionary,
# using ImportFormat type from schema.
encoded = rta_vrte_key_import.encode(
’ImportFormat’, AES_count_0_key
)
成功编码将返回一个字节对象,该对象可以打印或写入文件。
# Print the encoded key to console.
print(’AES_count_0_key encoded:’)
print(encoded.hex().upper())
# And save it to a file.
print(’Writing AES_count_0_key to AES_count_0_key.hex file.’)
with open(’AES_count_0_key.hex’, ’wb’) as f:
f.write(encoded)
编码的密钥现在可以在运行时使用,并注入到密钥槽中。
11.3.3.3 Key Injection During Runtime
对密钥进行编码后(见第11.3.3.2节),可以将其注入到密钥槽中。
密钥注入代码可以分为五个不同的部分(注意,为了简洁起见,省略了ara::crypto和ara::core名称空间)。
- Load a key slot
加载一个密钥槽可以分为三个操作,第一个操作是创建一个InstanceSpecifier(识别我们想用于密钥注入的密钥槽),即将密钥存储在持久内存中的密钥槽。
RTA-VRTE入门套件包括预定义的键槽,请参见第11.2.2.1节。
auto instanceSpec = InstanceSpecifier("CryptoQTProcess/
CryptoQTExecutable/RSCP_CryptoQTUser/customkeyslot1");
下一步是创建一个对象,用于访问机器上可用的密钥存储。请注意,LoadKeyStorageProvider
方法不采用任何参数,AUTOSAR规范——或者更准确地说是ara::crypto——假设只有一个(虚拟)密钥存储提供程序。
auto sp = LoadKeyStorageProvider();
最后一步是将选定的键槽加载到应用程序中。Load KeySlot方法返回一个密钥槽句柄,该句柄允许访问作为参数传递的InstanceSpecifier标识的密钥槽。
auto keySlot = sp->LoadKeySlot(instanceSpec).Value();
- Select the Crypto Provider
选择要用于密钥注入的加密提供程序与第一部分类似,因为它还创建了InstanceSpecifier。
请注意,RTA-VRTE Starter Kit只支持一个加密提供程序,Adaptive Applications在创建实例说明符时应使用字符串wolfssl(请参阅第11.2.2.1节)。之后,可以使用LoadCryptoProvider方法加载加密提供程序并将InstanceSpecifier作为参数。
const InstanceSpecifier cryptoProv("wolfssl");
cryp::CryptoProvider::Uptr cp = LoadCryptoProvider(cryptoProv);
- Open the key slot
现在需要打开加载的键槽-如果不打开键槽,我们就无法使用它。当调用Open方法时,第二个参数控制是否在写访问模式下打开键槽。由于显而易见的原因,在注入密钥时,有必要对该密钥槽进行写访问,因此传递true,Open返回一个密钥句柄,允许直接对密钥执行操作。
// Open the key slot for injection
// (second parameter set to true -> write access)
auto ioi = keySlot->Open(false, true).Value();
- Prepare the crypto object
第四步的重点是准备一个要注入或导入到键槽中的对象。将编码密钥引入自适应应用程序时存在多个选项。例如,可以通过网络从密钥服务器检索编码的密钥,或者直接从机器上的文件中读取。
为了清楚起见,此示例对自适应应用程序的源代码中的编码密钥进行了硬编码。
// Encoded key stored as a vector of bytes
// COUNT_0 from CBCMMT128.rsp file
const std::vector<std::uint8_t> input
0x30, 0x30, 0x81, 0x01, 0x00, 0x82, 0x01, 0x00,
0x83,
0x01, 0x01, 0x84, 0x01, 0x01, 0x85, 0x01, 0x10,
0x86,
0x01, 0x01, 0x87, 0x01, 0x01, 0x88, 0x01, 0x03,
0x89,
0x01, 0x00, 0x8a, 0x01, 0x00, 0x8b, 0x10, 0x1f,
0x8e,
0x49, 0x73, 0x95, 0x3f, 0x3f, 0xb0, 0xbd, 0x6b,
0x16,
0x66, 0x2e, 0x9a, 0x3c, 0x17
;
一旦编码的密钥可用于应用程序,就可以将其封装在ReadOnlyMemRegion中,并可以在下面的步骤中将其注入到密钥槽中。
ReadOnlyMemRegion inDatainput.data(), input.size();
- 密钥注入最后,密钥可以被注入到插槽中。使用ImportPublicObject方法执行注入,该方法将密钥句柄作为第一个参数,将编码密钥作为第二个参数,并将ara::crypto::CryptoObjectType::k未定义为第三个参数(对象的类型已在RTA-VRTE Starter Kit ASN.1导入模式中指定,请参阅第11.3.3.1节)。
auto importResult = cp->ImportPublicObject(*ioi,
inData, CryptoObjectType::kUndefined);
在成功调用ImportPublicObject方法之后,密钥注入就完成了,可以使用该密钥。
11.3.4 Encryption and Decryption
本节将介绍一些执行加密和解密的示例代码(请注意,为了简洁起见,省略了ara::crypto和ara::core命名空间)。
11.3.4.1 Encryption
加密代码可以分为六个不同的部分:
1. Load a key slot
加载钥匙槽包括三个简单操作,如第11.3.3.3节所述。简而言之,InstanceSpecifier标识存储密钥的密钥槽,LoadKeySlot方法创建一个密钥槽句柄,该句柄提供对密钥的访问。
auto instanceSpec = InstanceSpecifier("CryptoQTProcess/
CryptoQTExecutable/RSCP_CryptoQTUser/customkeyslot1");
auto sp = LoadKeyStorageProvider();
auto keySlot = sp->LoadKeySlot(instanceSpec).Value();
2. Select the crypto provider
在第二步中,我们加载要用于执行加密的加密提供程序,该步骤在第11.3.3.3节中进行了描述。
const InstanceSpecifier cryptoProv("wolfssl");
cryp::CryptoProvider::Uptr cp =
LoadCryptoProvider(cryptoProv);
3. Load the key
加载的钥匙槽现在需要使用Open方法打开(如果不打开钥匙槽,我们就无法访问存储在里面的钥匙)。打开密钥后,加密提供程序可以从该密钥槽加载密钥,以便直接访问该密钥,然后在加密操作期间使用该密钥。
auto resultIoi = keySlot->Open(false, false);
auto aesKey = cp->LoadSymmetricKey(*(resultIoi.Value()));
4.准备用于加密的对象
在本节中,我们准备用于加密的数据。我们正在使用NIST的测试矢量[12]。
// Test vector COUNT_0 from CBCMMT128.rsp file
// Data is stored as a vector of bytes
const std::vector<std::uint8_t> initializationVector
0x2f, 0xe2, 0xb3, 0x33, 0xce, 0xda, 0x8f, 0x98,
0xf4, 0xa9, 0x9b, 0x40, 0xd2, 0xcd, 0x34, 0xa8
;
const std::vector<std::uint8_t> plainText
0x45, 0xcf, 0x12, 0x96, 0x4f, 0xc8, 0x24, 0xab,
0x76, 0x61, 0x6a, 0xe2, 0xf4, 0xbf, 0x08, 0x22
;
const std::vector<std::uint8_t> cipherText
0x0f, 0x61, 0xc4, 0xd4, 0x4c, 0x51, 0x47, 0xc0,
0x3c, 0x19, 0x5a, 0xd7, 0xe2, 0xcc, 0x12, 0xb2
;
在我们可以将数据与ara::crypto API一起使用之前,我们需要将其封装在ReadOnlyMemRegion中。对于加密,我们需要包装初始化向量和纯文本(即未加密的数据)。
ReadOnlyMemRegion initializationVectorWrap
initializationVector.data(),
initializationVector.size();
ReadOnlyMemRegion plainTextWrap
plainText.data(), plainText.size();
5.准备加密上下文
首先,为正在使用的加密算法找到供应商特定的ID。这是通过ConvertToAlgId方法完成的。作为输入,传递一个字符串,该字符串符合加密基元的AUTOSAR命名约定。RTA-VRTE入门套件V3.0.0支持的算法列表可在第11.2.3节中找到,“算法名称”列用作输入参数。
在第二步中,创建一个加密上下文——一个将执行加密计算的对象。该算法是通过将其算法ID作为输入参数来指定的。最后,指定要执行的密钥和操作类型,在这种情况下是加密。
std::uint64_t algoID = cp->ConvertToAlgId("CBC/AES-128/PKCS7");
cryp::StreamCipherCtx::Uptr encryptionCtx = cp->CreateStreamCipherCtx(algoID).Value();
encryptionCtx->SetKey(*aesKey.Value(),
CryptoTransform::kEncrypt);
6.执行加密
对于每个基于流密码的加密计算,调用Start和FinishBytes方法。该算法需要一个初始化向量,因此它作为参数传递给Start方法。FinishBytes方法接收未加密的数据作为输入,并向其添加填充。添加填充是为了将输入数据的大小增加到块大小的倍数(如果输入数据的尺寸已经是块大小的多倍,则添加整个填充块)。然后,在该示例中,它返回加密的数据。在这个调用之后,加密过程就结束了。
encryptionCtx->Start(initializationVectorWrap);
auto encryptedText =
encryptionCtx->FinishBytes(plainTextWrap).Value();
在开发阶段,检查刚刚计算的加密文本(不包括填充)是否与预期值匹配可能很有用。此步骤告诉加密(作为功能集群)是否正确部署。为了增加置信度,使用公开可用的测试向量(例如本文件中使用的NIST[12]向量)。
11.3.4.2 Decryption
解密与加密非常相似,只是在几个关键位置有所不同。加载密钥槽、选择加密提供程序和加载密钥的步骤是相同的(为了简洁,这里不再重复这些步骤的描述)。然而,有三个主要区别:
1.准备用于解密的对象
使用了来自NIST[12]的相同测试向量,因此除了预期的加密填充文本之外,数据保持不变。
// Data is stored as a vector of bytes
const std::vector<std::uint8_t> paddingText
0x4c, 0x32, 0x37, 0xfc, 0x66, 0xa0, 0x7f, 0x6a,
0x7d, 0x2b, 0x26, 0x7b, 0xde, 0x1c, 0xf2, 0x90
;
Next, combine the cipher text and the padding text.
接下来,组合密文和填充文本。
std::vector<std::uint8_t> paddedCipherText = cipherText;
paddedCipherText.insert(paddedCipherText.end(),
paddingText.begin(), paddingText.end());
Then, wrap the encrypted data into a ReadOnlyMemRegion.
然后,将加密的数据包装到ReadOnlyMemRegion中。
ReadOnlyMemRegion initializationVectorWrap
initializationVector.data(),
initializationVector.size();
ReadOnlyMemRegion cipherTextWrap
paddedCipherText.data(), paddedCipherText.size();
2.准备解密上下文
查找供应商特定算法ID的代码或创建加密上下文的代码没有更改。当指定了正在使用的密钥时,在这种情况下解密还需要指定正在执行的操作类型:
std::uint64_t algoID = cp->ConvertToAlgId("CBC/AES-128/PKCS7");
cryp::StreamCipherCtx::Uptr decryptionCtx =
cp->CreateStreamCipherCtx(algoID).Value();
decryptionCtx->SetKey(*aesKey.Value(),
CryptoTransform::kDecrypt);
3.执行解密
对于解密,还需要调用Start和FinishBytes方法。
对Start的调用保持不变–也将初始化向量传递到此处。然而,当我们调用FinishBytes方法时,加密的数据会作为参数传递。
decryptionCtx->Start(initializationVectorWrap);
auto decryptedText = decryptionCtx->FinishBytes(cipherTextWrap).Value();
可以看出,用于解密的代码与用于加密的代码非常相似。要检查加密功能集群是否已正确部署,请将计算值与测试向量中的数据进行交叉检查:
详解AUTOSAR:什么是AUTOSAR?(理论篇—1)
目录
以上是关于Adaptive AUTOSAR——Cryptography (VRTE R21-11)的主要内容,如果未能解决你的问题,请参考以下文章