kopia lustrzana https://github.com/weetmuts/wmbusmeters
Add aescmac for more security modes.
rodzic
35ab71bf0d
commit
a6c73e10db
1
Makefile
1
Makefile
|
@ -89,6 +89,7 @@ $(BUILD)/%.o: src/%.cc $(wildcard src/%.h)
|
|||
|
||||
METER_OBJS:=\
|
||||
$(BUILD)/aes.o \
|
||||
$(BUILD)/aescmac.o \
|
||||
$(BUILD)/cmdline.o \
|
||||
$(BUILD)/config.o \
|
||||
$(BUILD)/dvparser.o \
|
||||
|
|
46
src/aes.cc
46
src/aes.cc
|
@ -21,10 +21,10 @@ ECB-AES128
|
|||
2b7e151628aed2a6abf7158809cf4f3c
|
||||
|
||||
resulting cipher
|
||||
3ad77bb40d7a3660a89ecaf32466ef97
|
||||
f5d3d58503b9699de785895a96fdbaaf
|
||||
43b1cd7f598ece23881b00e3ed030688
|
||||
7b0c785e27e8ad3f8223207104725dd4
|
||||
3ad77bb40d7a3660a89ecaf32466ef97
|
||||
f5d3d58503b9699de785895a96fdbaaf
|
||||
43b1cd7f598ece23881b00e3ed030688
|
||||
7b0c785e27e8ad3f8223207104725dd4
|
||||
|
||||
|
||||
NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0)
|
||||
|
@ -65,7 +65,7 @@ NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0)
|
|||
#define keyExpSize 176
|
||||
#endif
|
||||
|
||||
// jcallan@github points out that declaring Multiply as a function
|
||||
// jcallan@github points out that declaring Multiply as a function
|
||||
// reduces code size considerably with the Keil ARM compiler.
|
||||
// See this link for more information: https://github.com/kokke/tiny-AES128-C/pull/3
|
||||
#ifndef MULTIPLY_AS_A_FUNCTION
|
||||
|
@ -92,7 +92,7 @@ static const uint8_t* Key;
|
|||
#endif
|
||||
|
||||
// The lookup-tables are marked const so they can be placed in read-only storage instead of RAM
|
||||
// The numbers below can be computed dynamically trading ROM for RAM -
|
||||
// The numbers below can be computed dynamically trading ROM for RAM -
|
||||
// This can be useful in (embedded) bootloader applications, where ROM is often limited.
|
||||
static const uint8_t sbox[256] = {
|
||||
//0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
|
@ -131,7 +131,7 @@ static const uint8_t rsbox[256] = {
|
|||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };
|
||||
|
||||
// The round constant word array, Rcon[i], contains the values given by
|
||||
// The round constant word array, Rcon[i], contains the values given by
|
||||
// x to th e power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8)
|
||||
static const uint8_t Rcon[11] = {
|
||||
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };
|
||||
|
@ -141,8 +141,8 @@ static const uint8_t Rcon[11] = {
|
|||
* that you can remove most of the elements in the Rcon array, because they are unused.
|
||||
*
|
||||
* From Wikipedia's article on the Rijndael key schedule @ https://en.wikipedia.org/wiki/Rijndael_key_schedule#Rcon
|
||||
*
|
||||
* "Only the first some of these constants are actually used – up to rcon[10] for AES-128 (as 11 round keys are needed),
|
||||
*
|
||||
* "Only the first some of these constants are actually used – up to rcon[10] for AES-128 (as 11 round keys are needed),
|
||||
* up to rcon[8] for AES-192, up to rcon[7] for AES-256. rcon[0] is not used in AES algorithm."
|
||||
*
|
||||
* ... which is why the full array below has been 'disabled' below.
|
||||
|
@ -180,12 +180,12 @@ static uint8_t getSBoxInvert(uint8_t num)
|
|||
return rsbox[num];
|
||||
}
|
||||
|
||||
// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states.
|
||||
// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states.
|
||||
static void KeyExpansion(void)
|
||||
{
|
||||
uint32_t i, k;
|
||||
uint8_t tempa[4]; // Used for the column/row operations
|
||||
|
||||
|
||||
// The first round key is the key itself.
|
||||
for (i = 0; i < Nk; ++i)
|
||||
{
|
||||
|
@ -220,7 +220,7 @@ static void KeyExpansion(void)
|
|||
tempa[3] = k;
|
||||
}
|
||||
|
||||
// SubWord() is a function that takes a four-byte input word and
|
||||
// SubWord() is a function that takes a four-byte input word and
|
||||
// applies the S-box to each of the four bytes to produce an output word.
|
||||
|
||||
// Function Subword()
|
||||
|
@ -287,14 +287,14 @@ static void ShiftRows(void)
|
|||
{
|
||||
uint8_t temp;
|
||||
|
||||
// Rotate first row 1 columns to left
|
||||
// Rotate first row 1 columns to left
|
||||
temp = (*state)[0][1];
|
||||
(*state)[0][1] = (*state)[1][1];
|
||||
(*state)[1][1] = (*state)[2][1];
|
||||
(*state)[2][1] = (*state)[3][1];
|
||||
(*state)[3][1] = temp;
|
||||
|
||||
// Rotate second row 2 columns to left
|
||||
// Rotate second row 2 columns to left
|
||||
temp = (*state)[0][2];
|
||||
(*state)[0][2] = (*state)[2][2];
|
||||
(*state)[2][2] = temp;
|
||||
|
@ -322,7 +322,7 @@ static void MixColumns(void)
|
|||
uint8_t i;
|
||||
uint8_t Tmp,Tm,t;
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
{
|
||||
t = (*state)[i][0];
|
||||
Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ;
|
||||
Tm = (*state)[i][0] ^ (*state)[i][1] ; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp ;
|
||||
|
@ -360,7 +360,7 @@ static void InvMixColumns(void)
|
|||
int i;
|
||||
uint8_t a, b, c, d;
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
{
|
||||
a = (*state)[i][0];
|
||||
b = (*state)[i][1];
|
||||
c = (*state)[i][2];
|
||||
|
@ -392,14 +392,14 @@ static void InvShiftRows(void)
|
|||
{
|
||||
uint8_t temp;
|
||||
|
||||
// Rotate first row 1 columns to right
|
||||
// Rotate first row 1 columns to right
|
||||
temp = (*state)[3][1];
|
||||
(*state)[3][1] = (*state)[2][1];
|
||||
(*state)[2][1] = (*state)[1][1];
|
||||
(*state)[1][1] = (*state)[0][1];
|
||||
(*state)[0][1] = temp;
|
||||
|
||||
// Rotate second row 2 columns to right
|
||||
// Rotate second row 2 columns to right
|
||||
temp = (*state)[0][2];
|
||||
(*state)[0][2] = (*state)[2][2];
|
||||
(*state)[2][2] = temp;
|
||||
|
@ -423,8 +423,8 @@ static void Cipher(void)
|
|||
uint8_t round = 0;
|
||||
|
||||
// Add the First round key to the state before starting the rounds.
|
||||
AddRoundKey(0);
|
||||
|
||||
AddRoundKey(0);
|
||||
|
||||
// There will be Nr rounds.
|
||||
// The first Nr-1 rounds are identical.
|
||||
// These Nr-1 rounds are executed in the loop below.
|
||||
|
@ -435,7 +435,7 @@ static void Cipher(void)
|
|||
MixColumns();
|
||||
AddRoundKey(round);
|
||||
}
|
||||
|
||||
|
||||
// The last round is given below.
|
||||
// The MixColumns function is not here in the last round.
|
||||
SubBytes();
|
||||
|
@ -448,7 +448,7 @@ static void InvCipher(void)
|
|||
uint8_t round=0;
|
||||
|
||||
// Add the First round key to the state before starting the rounds.
|
||||
AddRoundKey(Nr);
|
||||
AddRoundKey(Nr);
|
||||
|
||||
// There will be Nr rounds.
|
||||
// The first Nr-1 rounds are identical.
|
||||
|
@ -460,7 +460,7 @@ static void InvCipher(void)
|
|||
AddRoundKey(round);
|
||||
InvMixColumns();
|
||||
}
|
||||
|
||||
|
||||
// The last round is given below.
|
||||
// The MixColumns function is not here in the last round.
|
||||
InvShiftRows();
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
Copyright (C) 2020 Fredrik Öhrström
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include<stdio.h>
|
||||
#include<memory.h>
|
||||
#include"aes.h"
|
||||
#include"aescmac.h"
|
||||
#include"util.h"
|
||||
|
||||
uchar vec87[16] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87
|
||||
};
|
||||
|
||||
void generateSubkeys(uchar *key, uchar *K1, uchar *K2)
|
||||
{
|
||||
uchar L[16];
|
||||
uchar Z[16];
|
||||
uchar tmp[16];
|
||||
|
||||
memset(Z, 0, 16);
|
||||
|
||||
AES_ECB_encrypt(Z, key, L, 16);
|
||||
|
||||
if (!(L[0] & 0x80))
|
||||
{
|
||||
shiftLeft(L, K1, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
shiftLeft(L, tmp, 16);
|
||||
xorit(tmp, vec87, K1, 16);
|
||||
}
|
||||
|
||||
if (!(K1[0] & 0x80))
|
||||
{
|
||||
shiftLeft(K1, K2, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
shiftLeft(K1, tmp, 16);
|
||||
xorit(tmp, vec87, K2, 16);
|
||||
}
|
||||
}
|
||||
|
||||
void pad(uchar *in, uchar *out, int len)
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if (i < len)
|
||||
{
|
||||
out[i] = in[i];
|
||||
}
|
||||
else if (i == len)
|
||||
{
|
||||
out[i] = 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
out[i] = 0x00;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AES_CMAC(uchar *key, uchar *input, int len, uchar *mac)
|
||||
{
|
||||
bool len_is_multiple_of_block;
|
||||
uchar X[16], Y[16];
|
||||
uchar K1[16], K2[16];
|
||||
uchar M_last[16], padded[16];
|
||||
|
||||
generateSubkeys(key, K1, K2);
|
||||
|
||||
int num_blocks = (len+15)/16;
|
||||
|
||||
if (!num_blocks)
|
||||
{
|
||||
num_blocks = 1;
|
||||
len_is_multiple_of_block = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
len_is_multiple_of_block = !(len%16);
|
||||
}
|
||||
|
||||
if (len_is_multiple_of_block)
|
||||
{
|
||||
xorit(input+(16*(num_blocks-1)), K1, M_last, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
pad(input+(16*(num_blocks-1)), padded, len%16);
|
||||
xorit(padded, K2, M_last, 16);
|
||||
}
|
||||
|
||||
memset(X, 0, 16);
|
||||
|
||||
for (int i=0; i<num_blocks-1; i++)
|
||||
{
|
||||
xorit(X, input+(16*i), Y, 16);
|
||||
AES_ECB_encrypt(Y, key, X, 16);
|
||||
}
|
||||
|
||||
xorit(X,M_last,Y, 16);
|
||||
AES_ECB_encrypt(Y, key, X, 16);
|
||||
|
||||
memcpy(mac, X, 16);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
Copyright (C) 2020 Fredrik Öhrström
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _AESCMAC_H_
|
||||
#define _AESCMAC_H_
|
||||
|
||||
typedef unsigned char uchar;
|
||||
|
||||
void AES_CMAC (uchar *key, uchar *input, int length, uchar *mac);
|
||||
|
||||
#endif //_AESCMAC_H_
|
|
@ -15,6 +15,7 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include"aescmac.h"
|
||||
#include"cmdline.h"
|
||||
#include"config.h"
|
||||
#include"meters.h"
|
||||
|
@ -32,6 +33,7 @@ int test_crc();
|
|||
int test_dvparser();
|
||||
int test_linkmodes();
|
||||
void test_ids();
|
||||
void test_kdf();
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
@ -45,6 +47,7 @@ int main(int argc, char **argv)
|
|||
test_dvparser();
|
||||
test_linkmodes();
|
||||
test_ids();
|
||||
test_kdf();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -411,3 +414,33 @@ void eqn(int a, int b, const char *tn)
|
|||
printf("ERROR in test %s expected %d to be equal to %d\n", tn, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void test_kdf()
|
||||
{
|
||||
vector<uchar> key;
|
||||
vector<uchar> input;
|
||||
vector<uchar> mac;
|
||||
|
||||
hex2bin("2b7e151628aed2a6abf7158809cf4f3c", &key);
|
||||
mac.resize(16);
|
||||
|
||||
AES_CMAC(&key[0], &input[0], 0, &mac[0]);
|
||||
string s = bin2hex(mac);
|
||||
string ex = "BB1D6929E95937287FA37D129B756746";
|
||||
if (s != ex)
|
||||
{
|
||||
printf("ERROR in aes-cmac expected \"%s\" but got \"%s\"\n", ex.c_str(), s.c_str());
|
||||
}
|
||||
|
||||
|
||||
input.clear();
|
||||
hex2bin("6bc1bee22e409f96e93d7e117393172a", &input);
|
||||
AES_CMAC(&key[0], &input[0], 16, &mac[0]);
|
||||
s = bin2hex(mac);
|
||||
ex = "070A16B46B4D4144F79BDD9DD04A287C";
|
||||
|
||||
if (s != ex)
|
||||
{
|
||||
printf("ERROR in aes-cmac expected \"%s\" but got \"%s\"\n", ex.c_str(), s.c_str());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
X(RelativeHumidity,RH) \
|
||||
X(HCA,HCA) \
|
||||
X(Text,TXT) \
|
||||
|
||||
X(Time,Seconds) \
|
||||
|
||||
#define LIST_OF_UNITS \
|
||||
X(KWH,kwh,kWh,Energy,"kilo Watt hour") \
|
||||
|
@ -44,6 +44,7 @@
|
|||
X(RH,rh,RH,RelativeHumidity,"relative humidity") \
|
||||
X(HCA,hca,hca,HCA,"heat cost allocation") \
|
||||
X(TXT,txt,txt,Text,"text") \
|
||||
X(Seconds,s,s,Time,"seconds") \
|
||||
|
||||
enum class Unit
|
||||
{
|
||||
|
|
13
src/util.cc
13
src/util.cc
|
@ -224,6 +224,19 @@ void xorit(uchar *srca, uchar *srcb, uchar *dest, int len)
|
|||
for (int i=0; i<len; ++i) { dest[i] = srca[i]^srcb[i]; }
|
||||
}
|
||||
|
||||
void shiftLeft(uchar *srca, uchar *srcb, int len)
|
||||
{
|
||||
uchar overflow = 0;
|
||||
|
||||
for (int i = len-1; i >= 0; i--)
|
||||
{
|
||||
srcb[i] = srca[i] << 1;
|
||||
srcb[i] |= overflow;
|
||||
overflow = (srca[i] & 0x80) >> 7;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
string format3fdot3f(double v)
|
||||
{
|
||||
string r;
|
||||
|
|
|
@ -50,6 +50,7 @@ std::string strdate(struct tm *date);
|
|||
std::string strdatetime(struct tm *date);
|
||||
|
||||
void xorit(uchar *srca, uchar *srcb, uchar *dest, int len);
|
||||
void shiftLeft(uchar *srca, uchar *srcb, int len);
|
||||
std::string format3fdot3f(double v);
|
||||
bool enableLogfile(std::string logfile, bool daemon);
|
||||
void disableLogfile();
|
||||
|
|
114
src/wmbus.cc
114
src/wmbus.cc
|
@ -15,6 +15,7 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include"aescmac.h"
|
||||
#include"wmbus.h"
|
||||
#include"wmbus_utils.h"
|
||||
#include"dvparser.h"
|
||||
|
@ -958,10 +959,10 @@ bool Telegram::parseELL(vector<uchar>::iterator &pos, MeterKeys *meter_keys)
|
|||
// All ELL:s (including ELL I) start with cc,acc.
|
||||
|
||||
ell_cc = *pos;
|
||||
addExplanationAndIncrementPos(pos, 1, "%02x cc-field (%s)", ell_cc, ccType(ell_cc).c_str());
|
||||
addExplanationAndIncrementPos(pos, 1, "%02x ell-cc (%s)", ell_cc, ccType(ell_cc).c_str());
|
||||
|
||||
ell_acc = *pos;
|
||||
addExplanationAndIncrementPos(pos, 1, "%02x ell-acc-field", ell_acc);
|
||||
addExplanationAndIncrementPos(pos, 1, "%02x ell-acc", ell_acc);
|
||||
|
||||
bool has_target_mft_address = false;
|
||||
bool has_session_number_pl_crc = false;
|
||||
|
@ -991,7 +992,7 @@ bool Telegram::parseELL(vector<uchar>::iterator &pos, MeterKeys *meter_keys)
|
|||
ell_mfct_b[0] = *(pos+0);
|
||||
ell_mfct_b[1] = *(pos+1);
|
||||
|
||||
addExplanationAndIncrementPos(pos, 2, "%02x%02x mfct2", ell_mfct_b[0], ell_mfct_b[1]);
|
||||
addExplanationAndIncrementPos(pos, 2, "%02x%02x ell-mfct2", ell_mfct_b[0], ell_mfct_b[1]);
|
||||
|
||||
ell_addr_b[0] = *(pos+0);
|
||||
ell_addr_b[1] = *(pos+1);
|
||||
|
@ -1000,7 +1001,7 @@ bool Telegram::parseELL(vector<uchar>::iterator &pos, MeterKeys *meter_keys)
|
|||
ell_addr_b[4] = *(pos+4);
|
||||
ell_addr_b[5] = *(pos+5);
|
||||
|
||||
addExplanationAndIncrementPos(pos, 6, "%02x%02x%02x%02x%02x%02x adr2",
|
||||
addExplanationAndIncrementPos(pos, 6, "%02x%02x%02x%02x%02x%02x ell-adr2",
|
||||
ell_addr_b[0], ell_addr_b[1], ell_addr_b[2],
|
||||
ell_addr_b[3], ell_addr_b[4], ell_addr_b[5]);
|
||||
}
|
||||
|
@ -1115,12 +1116,12 @@ bool Telegram::parseAFL(vector<uchar>::iterator &pos)
|
|||
afl_counter_b[1] = *(pos+1);
|
||||
afl_counter_b[2] = *(pos+2);
|
||||
afl_counter_b[3] = *(pos+3);
|
||||
afl_counter = afl_counter_b[0] << 24 |
|
||||
afl_counter_b[1] << 16 |
|
||||
afl_counter_b[2] << 8 |
|
||||
afl_counter_b[3];
|
||||
afl_counter = afl_counter_b[3] << 24 |
|
||||
afl_counter_b[2] << 16 |
|
||||
afl_counter_b[1] << 8 |
|
||||
afl_counter_b[0];
|
||||
|
||||
addExplanationAndIncrementPos(pos, 4, "%02x%02x%02x%02x afl-counter (%d)",
|
||||
addExplanationAndIncrementPos(pos, 4, "%02x%02x%02x%02x afl-counter (%u)",
|
||||
afl_counter_b[0],afl_counter_b[1],
|
||||
afl_counter_b[2],afl_counter_b[3],
|
||||
afl_counter);
|
||||
|
@ -1265,9 +1266,42 @@ bool Telegram::parseTPLConfig(std::vector<uchar>::iterator &pos)
|
|||
int m = (tpl_cfg >> 8) & 0x1f;
|
||||
tpl_sec_mode = fromIntToTPLSecurityMode(m);
|
||||
}
|
||||
bool has_cfg_ext = false;
|
||||
string info = toStringFromTPLConfig(tpl_cfg);
|
||||
info += " ";
|
||||
if (tpl_sec_mode == TPLSecurityMode::AES_CBC_NO_IV) // Security mode 7
|
||||
{
|
||||
tpl_num_encr_blocks = (tpl_cfg >> 4) & 0x0f;
|
||||
info += "NEB=";
|
||||
info += to_string(tpl_num_encr_blocks);
|
||||
info += " ";
|
||||
has_cfg_ext = true;
|
||||
}
|
||||
addExplanationAndIncrementPos(pos, 2, "%02x%02x tpl-cfg (%s)", cfg1, cfg2, info.c_str());
|
||||
|
||||
if (has_cfg_ext)
|
||||
{
|
||||
tpl_cfg_ext = *(pos+0);
|
||||
tpl_kdf_selection = (tpl_cfg_ext >> 4) & 3;
|
||||
|
||||
addExplanationAndIncrementPos(pos, 1, "%02x tpl-cfg-ext (KDFS=%d)", tpl_cfg_ext, tpl_kdf_selection);
|
||||
|
||||
if (tpl_kdf_selection == 1)
|
||||
{
|
||||
vector<uchar> key;
|
||||
vector<uchar> input;
|
||||
vector<uchar> mac;
|
||||
|
||||
mac.resize(16);
|
||||
|
||||
|
||||
AES_CMAC(&key[0], &input[0], 16, &mac[0]);
|
||||
string s = bin2hex(mac);
|
||||
tpl_generated_key.clear();
|
||||
tpl_generated_key.insert(tpl_generated_key.end(), mac.begin(), mac.end());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1305,7 +1339,7 @@ bool Telegram::parseLongTPL(std::vector<uchar>::iterator &pos)
|
|||
tpl_version = *(pos+0);
|
||||
addExplanationAndIncrementPos(pos, 1, "%02x tpl-version", tpl_version);
|
||||
|
||||
tpl_type = *(pos+1);
|
||||
tpl_type = *(pos+0);
|
||||
string info = mediaType(tpl_type);
|
||||
addExplanationAndIncrementPos(pos, 1, "%02x tpl-type (%s)", tpl_type, info.c_str());
|
||||
|
||||
|
@ -1316,11 +1350,42 @@ bool Telegram::parseLongTPL(std::vector<uchar>::iterator &pos)
|
|||
|
||||
bool loadFormatBytesFromSignature(uint16_t format_signature, vector<uchar> *format_bytes);
|
||||
|
||||
bool Telegram::parse_TPL_72(vector<uchar>::iterator &pos)
|
||||
bool Telegram::potentiallyDecrypt(vector<uchar>::iterator &pos, MeterKeys *meter_keys)
|
||||
{
|
||||
if (tpl_sec_mode == TPLSecurityMode::AES_CBC_IV)
|
||||
{
|
||||
bool ok = decrypt_TPL_AES_CBC_IV(this, frame, pos, meter_keys->confidentiality_key);
|
||||
if (!ok) return false;
|
||||
// Now the frame from pos and onwards has been decrypted.
|
||||
|
||||
if (*(pos+0) != 0x2f || *(pos+1) != 0x2f)
|
||||
{
|
||||
if (parser_warns_) warning("(wmbus) decrypted content failed check, did you use the correct decryption key?\n");
|
||||
}
|
||||
addExplanationAndIncrementPos(pos, 2, "%02x%02x decrypt check bytes", *(pos+0), *(pos+1));
|
||||
}
|
||||
else if (tpl_sec_mode == TPLSecurityMode::AES_CBC_NO_IV)
|
||||
{
|
||||
bool ok = decrypt_TPL_AES_CBC_NO_IV(this, frame, pos, tpl_generated_key);
|
||||
if (!ok) return false;
|
||||
// Now the frame from pos and onwards has been decrypted.
|
||||
|
||||
if (*(pos+0) != 0x2f || *(pos+1) != 0x2f)
|
||||
{
|
||||
if (parser_warns_) warning("(wmbus) decrypted content failed check, did you use the correct decryption key?\n");
|
||||
}
|
||||
addExplanationAndIncrementPos(pos, 2, "%02x%02x decrypt check bytes", *(pos+0), *(pos+1));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Telegram::parse_TPL_72(vector<uchar>::iterator &pos, MeterKeys *meter_keys)
|
||||
{
|
||||
bool ok = parseLongTPL(pos);
|
||||
if (!ok) return false;
|
||||
|
||||
potentiallyDecrypt(pos, meter_keys);
|
||||
|
||||
header_size = distance(frame.begin(), pos);
|
||||
int remaining = distance(pos, frame.end());
|
||||
suffix_size = 0;
|
||||
|
@ -1384,30 +1449,7 @@ bool Telegram::parse_TPL_7A(vector<uchar>::iterator &pos, MeterKeys *meter_keys)
|
|||
bool ok = parseShortTPL(pos);
|
||||
if (!ok) return false;
|
||||
|
||||
if (tpl_sec_mode == TPLSecurityMode::AES_CBC_IV)
|
||||
{
|
||||
bool ok = decrypt_TPL_AES_CBC_IV(this, frame, pos, meter_keys->confidentiality_key);
|
||||
if (!ok) return false;
|
||||
// Now the frame from pos and onwards has been decrypted.
|
||||
|
||||
if (*(pos+0) != 0x2f || *(pos+1) != 0x2f)
|
||||
{
|
||||
if (parser_warns_) warning("(wmbus) decrypted content failed check, did you use the correct decryption key?\n");
|
||||
}
|
||||
addExplanationAndIncrementPos(pos, 2, "%02x%02x decrypt check bytes", *(pos+0), *(pos+1));
|
||||
}
|
||||
else if (tpl_sec_mode == TPLSecurityMode::AES_CBC_NO_IV)
|
||||
{
|
||||
bool ok = decrypt_TPL_AES_CBC_NO_IV(this, frame, pos, meter_keys->confidentiality_key);
|
||||
if (!ok) return false;
|
||||
// Now the frame from pos and onwards has been decrypted.
|
||||
|
||||
if (*(pos+0) != 0x2f || *(pos+1) != 0x2f)
|
||||
{
|
||||
if (parser_warns_) warning("(wmbus) decrypted content failed check, did you use the correct decryption key?\n");
|
||||
}
|
||||
addExplanationAndIncrementPos(pos, 2, "%02x%02x decrypt check bytes", *(pos+0), *(pos+1));
|
||||
}
|
||||
potentiallyDecrypt(pos, meter_keys);
|
||||
|
||||
header_size = distance(frame.begin(), pos);
|
||||
int remaining = distance(pos, frame.end());
|
||||
|
@ -1438,7 +1480,7 @@ bool Telegram::parseTPL(vector<uchar>::iterator &pos, MeterKeys *meter_keys)
|
|||
|
||||
switch (tpl_ci)
|
||||
{
|
||||
case CI_Field_Values::TPL_72: return parse_TPL_72(pos);
|
||||
case CI_Field_Values::TPL_72: return parse_TPL_72(pos, meter_keys);
|
||||
case CI_Field_Values::TPL_78: return parse_TPL_78(pos);
|
||||
case CI_Field_Values::TPL_79: return parse_TPL_79(pos);
|
||||
case CI_Field_Values::TPL_7A: return parse_TPL_7A(pos, meter_keys);
|
||||
|
|
|
@ -277,6 +277,10 @@ struct Telegram
|
|||
int tpl_sts {}; // 1 byte
|
||||
int tpl_cfg {}; // 2 bytes
|
||||
TPLSecurityMode tpl_sec_mode {}; // Based on 5 bits extracted from cfg.
|
||||
int tpl_num_encr_blocks {};
|
||||
int tpl_cfg_ext {}; // 1 byte
|
||||
int tpl_kdf_selection {}; // 1 byte
|
||||
vector<uchar> tpl_generated_key; // 16 bytes
|
||||
|
||||
uchar tpl_id_b[4]; // 4 bytes
|
||||
uchar tpl_mft_b[2]; // 2 bytes
|
||||
|
@ -332,11 +336,11 @@ private:
|
|||
void printAFL();
|
||||
void printTPL();
|
||||
|
||||
bool parse_TPL_72(vector<uchar>::iterator &pos);
|
||||
bool parse_TPL_72(vector<uchar>::iterator &pos, MeterKeys *meter_keys);
|
||||
bool parse_TPL_78(vector<uchar>::iterator &pos);
|
||||
bool parse_TPL_79(vector<uchar>::iterator &pos);
|
||||
bool parse_TPL_7A(vector<uchar>::iterator &pos, MeterKeys *meter_keys);
|
||||
|
||||
bool potentiallyDecrypt(vector<uchar>::iterator &pos, MeterKeys *meter_keys);
|
||||
bool parseTPLConfig(std::vector<uchar>::iterator &pos);
|
||||
static string toStringFromELLSN(int sn);
|
||||
static string toStringFromTPLConfig(int cfg);
|
||||
|
|
Ładowanie…
Reference in New Issue