versadac  1
versadac - Scalable Recorder Firmware
DISE_encryption.h
1 // Copyright (c) 2012 Invensys Eurotherm Ltd.
3 //
4 // MODULE : DISE Crypto
5 // FILENAME : DISE_Crypto.h
6 // AUTHOR : Adrian Oliver
7 // CREATED : November 2012
8 // DESCRIPTION : Header file for Device IDM Symmetric Encryption:
10 // These functions will use Instrument database data to automatically generate
11 // Encryption/Decryption keys.
12 //
13 // Once the key has been generated, it uses the Authenticated Encryption/Decryption
14 // functions
15 //
16 // The Key generation is automatic - however on initialisation, the device/IDM
17 // needs to register here which instrument database parameters are to be used
18 // during the key generation. This is done by the host providing the
19 // structure - if this is not provided, this module will fail to link
20 //
21 // Note that two structures need to be provided:
22 //
23 // 1 - for when device is encrypting (i.e. read from device)
24 // 2 - for when device is decrypting (i.e. write to device).
25 //
26 // Yes - two DIFFERENT set of parameters are used for reading/writing
27 //
29 
30 #ifndef DeviceIDMSymmetricEncryption_H
31 #define DeviceIDMSymmetricEncryption_H
32 
34 #include "openssl/aes.h"
35 #include "AuthenticatedEncryption.h"
36 
39 // Some random constant used to help generate the IV
40 // **** TODO **** Good/recommended changing this on major updates
41 // **** NOTE **** MUST BE 32 Characters long
42 #define DeviceIDMSymmetricEncryption_IV_HMAC_KEY "uWZ2TUO_4ck=IRfL(K^mf6>f5pPT5Qkg"
43 
45 // Some random constant used to help initialise tjhe Nonce
46 // **** TODO **** Good/recommended changing this on major updates
47 // **** NOTE **** MUST BE 32 Characters long
48 #define DeviceIDMSymmetricEncryption_Nonce_HMAC_KEY "WdnMX2EoPCCWSDYWQ6iFc6Rh67WjsD1s"
49 
51 // The host MUST declare two lists of parameters used as source values/data
52 // used as input to the KDF, from which the encryption keys are generated
53 // Need a different list for reading, and a different list for writing
54 // This structure is a list of parameter CISPS/IDs
55 typedef struct
56 {
57  unsigned long cisp;
59 
62 // TODO - This MUST be declared by the host system - otherwise this will fail to link..
63 extern const DeviceIDMSymmetricEncryption_KDF_ParameterData_Record_Type DeviceIDMSymmetricEncryption_KDF_Parameters_For_Writing_To_Device[];
64 extern const DeviceIDMSymmetricEncryption_KDF_ParameterData_Record_Type DeviceIDMSymmetricEncryption_KDF_Parameters_For_Reading_From_Device[];
65 //
66 // Example Declaration
67 //const DeviceIDMSymmetricEncryption_KeyGenerationParameter_Record_Type DeviceIDMSymmetricEncryption_KDF_Parameters_For_Writing[] =
68 //{
69 // NETWORK_NETWORK_INT_MAC_C0SP,
70 // INSTRUMENT_INSTRUMENT_LOCALE_LANG_C0SP,
71 // NULL <**** NOTE THE NULL TERMINATION - OTHERWISE ALL WILL FAIL!
72 //}
73 
76 // TODO - This MUST be declared by the host system - otherwise this will fail to link..
77 extern const char* DeviceIDMSymmetricEncryption_KDF_Salt_For_Writing_To_Device; // *** MUST BE 16 CHARACTERS LONG - NO MORE, NO LESS ***
78 extern const char* DeviceIDMSymmetricEncryption_KDF_Salt_For_Reading_From_Device; // *** MUST BE 16 CHARACTERS LONG - NO MORE, NO LESS ***
79 //
80 // Example:
81 // const char* DeviceIDMSymmetricEncryption_KDF_Salt_For_Writing = "$DLJIUB7Rh8qCNL-";
82 
85 // TODO - This MUST be declared by the host system - otherwise this will fail to link..
86 extern const char* DeviceIDMSymmetricEncryption_KDF_FixedSourceKey_For_Writing_To_Device; // *** MUST BE 16 CHARACTERS LONG - NO MORE, NO LESS ***
87 extern const char* DeviceIDMSymmetricEncryption_KDF_FixedSourceKey_For_Reading_From_Device; // *** MUST BE 16 CHARACTERS LONG - NO MORE, NO LESS ***
88 //
89 // Example:
90 // const char* DeviceIDMSymmetricEncryption_KDF_FixedSourceKey_For_Writing = "Y+U=&OAik?t*,7KR";
91 
94 // To make this module as target independent as possible, we define a small
95 // wrapper function which will get the value data for us (plus some info...)
96 bool DeviceIDMSymmetricEncryption_ReadDeviceData(unsigned long CISP,
97  unsigned char* pDataBuffer, // if NULL, then only returns pRequiredDataBufferLength
98  unsigned int DataBufferLengthMaximum, // tells use the size available in pRequiredDataBufferLength
99  unsigned int* pIDMFlashMemoryAddress, // what address should this be read from?
100  unsigned int* pRequiredDataBufferLength // tells us how manys are/were required
101  ); // returns the data size in bytes
102 
106 {
107 public:
109 
111 
113  virtual void Initialise(const DeviceIDMSymmetricEncryption_KDF_ParameterData_Record_Type* pTable,
114  const char* pszKDF_Salt,
115  const char* pszKDF_FixedSourceKey,
116  const bool UseIV);
117 
119  void InitialiseDeviceDataInformation(void);
120 
122  void InitialiseNounce(unsigned long Seed);
123  void IncrementNounce();
124  unsigned long GetNounce();
125 
127  // these do nothing on the target built - need to be overridden by IDM
128  virtual void ParameterHasBeenUpdatedFromDevice(unsigned long CISP) {}
129 
130  virtual bool HaveAllParametersRequiredForKDFBeenUpdated(void){ return false;}
131 
132  virtual bool IsThisParameterRequiredForKDF(unsigned long CISP) { return false;}
133 
135  bool GetDeviceData(unsigned char* pDeviceDataBuffer, // Caller has to allocate this before
136  unsigned int DeviceDataBufferLength); // size of the DeviceDataBuffer
137 
138  bool GenerateKey(unsigned char* pKeyBuffer, // this is allocated and returned - the caller has to deallocate
139  unsigned int KeyBufferLength,
140  bool IncludeNonce = true);
141 
142  int GetTotalNumberOfParameters(void) { return m_KDF_DeviceData_TotalNumberOfParameters;}
143 
144  bool GenerateIV(char* pIVData);
145 
147  bool Encrypt(const unsigned char* DataIn,
148  const int DataInLength,
149  unsigned char* pCipherDataBuffer, // this is allocated and returned - the caller has to deallocate
150  unsigned int CipherDataBufferLength,
151  unsigned int* pCipherDataLength = NULL); // returns the overall cipher data length
152 
153  bool Decrypt(const unsigned char* CipherDataIn,
154  const int CipherDataInLength,
155  unsigned char* pDataOutBuffer, // this is allocated and returned - the caller has to deallocate
156  unsigned int DataOutBuffertLength);
157 
159  bool Encrypt(const unsigned char* DataIn,
160  const int DataInLength,
161  const unsigned char* KeyIn,
162  const int KeyInLength,
163  unsigned char* pCipherDataBuffer, // this is allocated and returned - the caller has to deallocate
164  unsigned int CipherDataBufferLength,
165  unsigned int* pCipherDataLength = NULL); // returns the overall cipher data length
166 
167  bool Decrypt(const unsigned char* CipherDataIn,
168  const int CipherDataInLength,
169  const unsigned char* KeyIn,
170  const int KeyInLength,
171  unsigned char* pDataOutBuffer, // this is allocated and returned - the caller has to deallocate
172  unsigned int DataOutBuffertLength);
173 
175 private:
177 
178  unsigned int m_KDF_DeviceData_TotalNumberOfParameters;
179  unsigned int m_KDF_DeviceData_RequiredBufferLength;
180 
181  char m_KDF_Salt[AES_BLOCK_SIZE + 1];
182  char m_KDF_FixedSourceKey[AES_BLOCK_SIZE + 1];
183 
184  unsigned long m_Nonce;
185  bool m_UseIV;
186 
188  // Keeps track of AES encryption - specially when repeated encryption/decryption
189  // with the same key...
191 };
192 
195 extern CDeviceIDMSymmetricEncryption* g_pDISE_EncryptDecrypt_For_Reading_From_Device;
196 extern CDeviceIDMSymmetricEncryption* g_pDISE_EncryptDecrypt_For_Writing_To_Device;
197 
199 
202 // Cryptographic ‘Nonce’ Counter
203 // One important security issue is a replay attack where an attacker can
204 // re-send an encrypted message they intercepted over the network. They
205 // could potentially record the entire device login message sequences from
206 // a real user and later replay them to successfully login to the same or
207 // other device.
208 //
209 // A common technique to stop replay attacks is to use an always incrementing
210 // message counter (nonce) which is used in the encryption process.
211 //
212 // This nonce would also ensure that when a genuine user re-sending the same
213 // valid password on consecutive logins, the cipher text would always be
214 // different. Without such Nonce, the cipher text on consecutive logins
215 // would most likely be identical – an attacker would simply replay all
216 // the messages to successfully login to the device.
217 //
218 // It is recommended that each time the device receives a new encrypted
219 // message (message write), it ALWAYS increments this nonce, irrespective
220 // of whether the message was deciphered successfully.
221 //
222 // This would force the sender (EuroMBus) to have to re-read this nonce,
223 // write the new value into the IDM, and re-generate the encryption key K
224 // to encrypt the message before being able to re-send an encrypted message.
225 // However this would ensure that the same message could never the re-used.
226 // Any message encrypted using a previous Nonce value could never be
227 // successfully decrypted again.
228 //
229 // To overcome potentially two completely identical (cloned) devices having
230 // the same start-up state, the Nonce should be initialised to a random
231 // value (e.g. on device cold-start, or initial factory startup/calibration).
232 // Special consideration needs to be made to ensure adequate entropy of the
233 // random function be used to initialise this Nonce. Specifically, if
234 // initialised during device cold start, the hardware random number
235 // generators used in multiple devices would normally be initialised to
236 // identical values, resulting in low entropy (i.e. potentially identical
237 // values).
238 //
239 // The device’s Nonce must be read-only – it must be impossible for any
240 // external input to be able to change the Nonce to any arbitrary value.
241 // It is recommended that Factory Plate not be able to change this value,
242 // as that also allows a potential attack mechanism.
243 //
244 // One potential attack mechanism is for an attacker to systematically change
245 // one device parameter at a time and observe the resulting change in the
246 // cipher text. Note that each attempt will (should) result in a different
247 // Nonce value, resulting in 2 changes for each attack attempt. Despite
248 // that, they will still not be able to predict the encryption key K (output
249 // of the KDF) as they do not know the value of the fixed salt (e.g. fixed
250 // password). Further, the KDF implementation is such that it is impossible
251 // to predict its output from a known change to its input.
252 
255 
257 #endif
258 
259 
Definition: DISE_encryption.h:105
Definition: AuthenticatedEncryption.h:21