Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
EIDFrame.cpp
00001 /* 00002 * Copyright (c) 2016, Google Inc, All Rights Reserved 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); you may 00006 * not use this file except in compliance with the License 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 #include "EIDFrame.h" 00019 #include "EddystoneService.h" 00020 #include "EntropySource/EntropySource.h" 00021 00022 EIDFrame::EIDFrame() 00023 { 00024 mbedtls_entropy_init(&entropy); 00025 // init entropy source 00026 eddystoneRegisterEntropySource(&entropy); 00027 // init Random 00028 mbedtls_ctr_drbg_init(&ctr_drbg); 00029 } 00030 00031 void EIDFrame::clearFrame(uint8_t* frame) { 00032 frame[FRAME_LEN_OFFSET] = 0; // Set frame length to zero to clear it 00033 } 00034 00035 00036 void EIDFrame::setData(uint8_t *rawFrame, int8_t advTxPower, const uint8_t* eidData) 00037 { 00038 size_t index = 0; 00039 rawFrame[index++] = EDDYSTONE_UUID_SIZE + EID_FRAME_LEN; // EID length + overhead of four bytes below 00040 rawFrame[index++] = EDDYSTONE_UUID[0]; // 16-bit Eddystone UUID 00041 rawFrame[index++] = EDDYSTONE_UUID[1]; 00042 rawFrame[index++] = FRAME_TYPE_EID; // 1B Type 00043 rawFrame[index++] = advTxPower; // 1B Power @ 0meter 00044 00045 memcpy(rawFrame + index, eidData, EID_LENGTH); // EID = 8 BYTE ID 00046 } 00047 00048 uint8_t* EIDFrame::getData(uint8_t* rawFrame) 00049 { 00050 return &(rawFrame[EID_DATA_OFFSET]); 00051 } 00052 00053 uint8_t EIDFrame::getDataLength(uint8_t* rawFrame) 00054 { 00055 return rawFrame[FRAME_LEN_OFFSET] - EDDYSTONE_UUID_LEN; 00056 } 00057 00058 uint8_t* EIDFrame::getAdvFrame(uint8_t* rawFrame) 00059 { 00060 return &(rawFrame[ADV_FRAME_OFFSET]); 00061 } 00062 00063 uint8_t EIDFrame::getAdvFrameLength(uint8_t* rawFrame) 00064 { 00065 return rawFrame[FRAME_LEN_OFFSET]; 00066 } 00067 00068 uint8_t* EIDFrame::getEid(uint8_t* rawFrame) 00069 { 00070 return &(rawFrame[EID_VALUE_OFFSET]); 00071 } 00072 00073 uint8_t EIDFrame::getEidLength(uint8_t* rawFrame) 00074 { 00075 return rawFrame[FRAME_LEN_OFFSET] - EID_HEADER_LEN; 00076 } 00077 00078 void EIDFrame::setAdvTxPower(uint8_t* rawFrame, int8_t advTxPower) 00079 { 00080 rawFrame[EID_TXPOWER_OFFSET] = advTxPower; 00081 } 00082 00083 // Mote: This is only called after the rotation period is due, or on writing/creating a new eidIdentityKey 00084 void EIDFrame::update(uint8_t* rawFrame, uint8_t* eidIdentityKey, uint8_t rotationPeriodExp, uint32_t timeSecs) 00085 { 00086 // Calculate the temporary key datastructure 1 00087 uint8_t ts[4]; // big endian representation of time 00088 ts[0] = (timeSecs >> 24) & 0xff; 00089 ts[1] = (timeSecs >> 16) & 0xff; 00090 00091 uint8_t tmpEidDS1[16] = { 0,0,0,0,0,0,0,0,0,0,0, SALT, 0, 0, ts[0], ts[1] }; 00092 00093 // Perform the aes encryption to generate the final temporary key. 00094 uint8_t tmpKey[16]; 00095 aes128Encrypt(eidIdentityKey, tmpEidDS1, tmpKey); 00096 00097 // Compute the EID 00098 uint8_t eid[16]; 00099 uint32_t scaledTime = (timeSecs >> rotationPeriodExp) << rotationPeriodExp; 00100 ts[0] = (scaledTime >> 24) & 0xff; 00101 ts[1] = (scaledTime >> 16) & 0xff; 00102 ts[2] = (scaledTime >> 8) & 0xff; 00103 ts[3] = scaledTime & 0xff; 00104 uint8_t tmpEidDS2[16] = { 0,0,0,0,0,0,0,0,0,0,0, rotationPeriodExp, ts[0], ts[1], ts[2], ts[3] }; 00105 aes128Encrypt(tmpKey, tmpEidDS2, eid); 00106 00107 // copy the leading 8 bytes of the eid result (full result length = 16) into the ADV frame 00108 memcpy(rawFrame + 5, eid, EID_LENGTH); 00109 00110 } 00111 00112 /** AES128 encrypts a 16-byte input array with a key, resulting in a 16-byte output array */ 00113 void EIDFrame::aes128Encrypt(uint8_t key[], uint8_t input[], uint8_t output[]) { 00114 mbedtls_aes_context ctx; 00115 mbedtls_aes_init(&ctx); 00116 mbedtls_aes_setkey_enc(&ctx, key, 8 * sizeof(Lock_t)); 00117 mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, input, output); 00118 mbedtls_aes_free(&ctx); 00119 } 00120 00121 int EIDFrame::genBeaconKeys(PrivateEcdhKey_t beaconPrivateEcdhKey, PublicEcdhKey_t beaconPublicEcdhKey) { 00122 mbedtls_ecdh_init( &ecdh_ctx ); 00123 00124 int i = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0); 00125 if (i != 0) { 00126 return i; // return EID_RND_FAIL; 00127 } 00128 00129 if (mbedtls_ecp_group_load(&ecdh_ctx.grp, MBEDTLS_ECP_DP_CURVE25519) != 0) { 00130 return EID_GRP_FAIL; 00131 } 00132 if (mbedtls_ecdh_gen_public(&ecdh_ctx.grp, &ecdh_ctx.d, &ecdh_ctx.Q, mbedtls_ctr_drbg_random, &ctr_drbg) != 0) { 00133 return EID_GENKEY_FAIL; 00134 } 00135 00136 mbedtls_mpi_write_binary(&ecdh_ctx.d, beaconPrivateEcdhKey, sizeof(PrivateEcdhKey_t)); 00137 mbedtls_mpi_write_binary(&ecdh_ctx.Q.X, beaconPublicEcdhKey, sizeof(PublicEcdhKey_t)); 00138 00139 mbedtls_ecdh_free( &ecdh_ctx ); 00140 return EID_SUCCESS; 00141 } 00142 00143 int EIDFrame::genEcdhSharedKey(PrivateEcdhKey_t beaconPrivateEcdhKey, PublicEcdhKey_t beaconPublicEcdhKey, PublicEcdhKey_t serverPublicEcdhKey, EidIdentityKey_t eidIdentityKey) { 00144 int16_t ret = 0; 00145 uint8_t tmp[32]; 00146 // initialize context 00147 mbedtls_ecdh_init( &ecdh_ctx ); 00148 mbedtls_ecp_group_load( &ecdh_ctx.grp, MBEDTLS_ECP_DP_CURVE25519 ); 00149 00150 // copy binary beacon private key (previously generated!) into context 00151 // Note: As the PrivateKey is generated locally, it is Big Endian 00152 ret = mbedtls_mpi_read_binary( &ecdh_ctx.d, beaconPrivateEcdhKey, sizeof(PrivateEcdhKey_t) ); 00153 00154 // copy server-public-key (received through GATT characteristic 10) into context 00155 ret = mbedtls_mpi_lset( &ecdh_ctx.Qp.Z, 1 ); 00156 EddystoneService::swapEndianArray(serverPublicEcdhKey, tmp, 32); // To make it Big Endian 00157 ret = mbedtls_mpi_read_binary( &ecdh_ctx.Qp.X, tmp , sizeof(PublicEcdhKey_t) ); 00158 00159 // ECDH point multiplication 00160 size_t olen; // actual size of shared secret 00161 uint8_t sharedSecret[32]; // shared ECDH secret 00162 memset(sharedSecret, 0, 32); 00163 ret = mbedtls_ecdh_calc_secret( &ecdh_ctx, &olen, sharedSecret, sizeof(sharedSecret), NULL, NULL ); 00164 LOG(("size of olen= %d ret=%x\r\n", olen, ret)); 00165 EddystoneService::swapEndianArray(sharedSecret, tmp, 32); 00166 memcpy(sharedSecret, tmp, 32); 00167 LOG(("Shared secret=")); EddystoneService::logPrintHex(sharedSecret, 32); 00168 if (olen != sizeof(sharedSecret)) { 00169 return EID_GENKEY_FAIL; 00170 } 00171 if (ret == MBEDTLS_ERR_ECP_BAD_INPUT_DATA) { 00172 return EID_RC_SS_IS_ZERO; 00173 } 00174 00175 // Convert the shared secret to key material using HKDF-SHA256. HKDF is used with 00176 // the salt set to a concatenation of the resolver's public key and beacon's 00177 // public key, with a null context. 00178 00179 // build HKDF key 00180 unsigned char k[ 64 ]; 00181 EddystoneService::swapEndianArray(beaconPublicEcdhKey, tmp, 32); 00182 memcpy( &k[0], serverPublicEcdhKey, sizeof(PublicEcdhKey_t) ); 00183 memcpy( &k[32], tmp, sizeof(PublicEcdhKey_t) ); 00184 00185 // compute HKDF: see https://tools.ietf.org/html/rfc5869 00186 // mbedtls_md_context_t md_ctx; 00187 mbedtls_md_init( &md_ctx ); 00188 mbedtls_md_setup( &md_ctx, mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ), 1 ); 00189 mbedtls_md_hmac_starts( &md_ctx, k, sizeof( k ) ); 00190 mbedtls_md_hmac_update( &md_ctx, sharedSecret, sizeof(sharedSecret) ); 00191 unsigned char prk[ 32 ]; 00192 mbedtls_md_hmac_finish( &md_ctx, prk ); 00193 mbedtls_md_hmac_starts( &md_ctx, prk, sizeof( prk ) ); 00194 const unsigned char const1[] = { 0x01 }; 00195 mbedtls_md_hmac_update( &md_ctx, const1, sizeof( const1 ) ); 00196 unsigned char t[ 32 ]; 00197 mbedtls_md_hmac_finish( &md_ctx, t ); 00198 00199 //Truncate the key material to 16 bytes (128 bits) to convert it to an AES-128 secret key. 00200 memcpy( eidIdentityKey, t, sizeof(EidIdentityKey_t) ); 00201 LOG(("\r\nEIDIdentityKey=")); EddystoneService::logPrintHex(t, 32); LOG(("\r\n")); 00202 00203 mbedtls_md_free( &md_ctx ); 00204 mbedtls_ecdh_free( &ecdh_ctx ); 00205 return EID_SUCCESS; 00206 }
Generated on Thu Jul 14 2022 09:28:18 by
1.7.2