raw
smg_comms_skeys_s...    1  -- Message reader & writers for SMG Communication Protocol
smg_comms_skeys_s... 2 -- S.MG, 2018
smg_comms_skeys_s... 3
smg_comms_skeys_s... 4 with Interfaces; use Interfaces;
smg_comms_skeys_s... 5 with Serpent;
smg_comms_skeys_s... 6 with System; use System;
smg_comms_files 7 with Ada.Assertions; use Ada.Assertions;
smg_comms_skeys_s... 8
smg_comms_skeys_s... 9 package body Messages is
smg_comms_skeys_s... 10
smg_comms_keymgm 11 ----------------------
smg_comms_keymgm 12 -- Serpent Messages --
smg_comms_keymgm 13 ----------------------
smg_comms_keymgm 14
smg_comms_skeys_s... 15 procedure Write_SKeys_SMsg( Keyset : in Serpent_Keyset;
smg_comms_skeys_s... 16 Counter : in Interfaces.Unsigned_16;
smg_comms_skeys_s... 17 Msg : out Raw_Types.Serpent_Msg) is
smg_comms_keymgm 18 begin
smg_comms_keymgm 19 -- call internal write on Octets with correct type id
smg_comms_keymgm 20 Write_SKeys( Keyset, Counter, SKeys_S_Type, Msg );
smg_comms_keymgm 21 end Write_SKeys_SMsg;
smg_comms_keymgm 22
smg_comms_keymgm 23
smg_comms_keymgm 24 -- Reads a Serpent keyset from given Serpent Message
smg_comms_keymgm 25 procedure Read_SKeys_SMsg( Msg : in Raw_Types.Serpent_Msg;
smg_comms_keymgm 26 Counter : out Interfaces.Unsigned_16;
smg_comms_keymgm 27 Keyset : out Serpent_Keyset) is
smg_comms_keymgm 28 begin
smg_comms_keymgm 29 -- check type id and call internal Read_SKeys if correct
smg_comms_keymgm 30 if Msg(Msg'First) /= SKeys_S_Type then
smg_comms_keymgm 31 raise Invalid_Msg;
smg_comms_keymgm 32 else
smg_comms_keymgm 33 Read_SKeys( Msg, Counter, Keyset );
smg_comms_keymgm 34 end if;
smg_comms_keymgm 35 end Read_SKeys_SMsg;
smg_comms_keymgm 36
smg_comms_keymgm 37 -- writes given key mgm structure into a Serpent message
smg_comms_keymgm 38 procedure Write_KMgm_SMsg( KMgm : in Keys_Mgm;
smg_comms_keymgm 39 Counter : in Interfaces.Unsigned_16;
smg_comms_keymgm 40 Msg : out Raw_Types.Serpent_Msg) is
smg_comms_keymgm 41 begin
smg_comms_keymgm 42 -- call internal write of key mgm with correct type ID
smg_comms_keymgm 43 Write_KMgm( KMgm, Counter, Key_Mgm_S_Type, Msg );
smg_comms_keymgm 44 end Write_KMgm_SMsg;
smg_comms_keymgm 45
smg_comms_keymgm 46 -- reads a key mgm structure from the given Serpent message
smg_comms_keymgm 47 procedure Read_KMgm_SMsg( Msg : in Raw_Types.Serpent_Msg;
smg_comms_keymgm 48 Counter : out Interfaces.Unsigned_16;
smg_comms_keymgm 49 KMgm : out Keys_Mgm) is
smg_comms_keymgm 50 begin
smg_comms_keymgm 51 -- check type id and call internal Read_KMgm if correct
smg_comms_keymgm 52 if Msg(Msg'First) /= Key_Mgm_S_Type then
smg_comms_keymgm 53 raise Invalid_Msg;
smg_comms_keymgm 54 else
smg_comms_keymgm 55 Read_KMgm( Msg, Counter, KMgm );
smg_comms_keymgm 56 end if;
smg_comms_keymgm 57 end Read_KMgm_SMsg;
smg_comms_keymgm 58
smg_comms_files 59 ------ File Transfer ------
smg_comms_files 60 procedure Write_File_Transfer( Chunk : in File_Chunk;
smg_comms_files 61 Msg : out Raw_Types.Serpent_Msg) is
smg_comms_files 62 Pos: Integer := Msg'First;
smg_comms_files 63 U16: Interfaces.Unsigned_16;
smg_comms_files 64 begin
smg_comms_files 65 -- write type ID
smg_comms_files 66 Msg(Pos) := File_Transfer_S_Type;
smg_comms_files 67 Pos := Pos + 1;
smg_comms_files 68
smg_comms_files 69 -- write filename as text field (size+2, text)
smg_comms_files 70 -- check against overflows
smg_comms_files 71 if Chunk.Name_Len > Text_Len'Last - 2 or
smg_comms_files 72 Pos + Integer(Chunk.Name_Len) + 2 > Msg'Last then
smg_comms_files 73 raise Invalid_Msg;
smg_comms_files 74 end if;
smg_comms_files 75
smg_comms_files 76 -- write total size: filename size + 2
smg_comms_files 77 U16 := Interfaces.Unsigned_16( Chunk.Name_Len + 2 );
smg_comms_files 78 Write_U16( Msg, Pos, U16 );
smg_comms_files 79
smg_comms_files 80 -- write filename
smg_comms_files 81 String_To_Octets( Chunk.Filename,
smg_comms_files 82 Msg(Pos..Pos+Integer(Chunk.Name_Len)-1) );
smg_comms_files 83 Pos := Pos + Integer(Chunk.Name_Len);
smg_comms_files 84
smg_comms_files 85 --write content
smg_comms_files 86 -- check against overflow, including the 2 octets for counter at the end
smg_comms_files 87 if Chunk.Len > Text_Len'Last - 2 or
smg_comms_files 88 Pos + Integer(Chunk.Len) + 4 > Msg'Last then
smg_comms_files 89 raise Invalid_Msg;
smg_comms_files 90 end if;
smg_comms_files 91
smg_comms_files 92 -- write total size for this text field
smg_comms_files 93 U16 := Interfaces.Unsigned_16( Chunk.Len + 2 );
smg_comms_files 94 Write_U16( Msg, Pos, U16 );
smg_comms_files 95
smg_comms_files 96 -- write actual content
smg_comms_files 97 Msg(Pos..Pos+Chunk.Content'Length-1) := Chunk.Content;
smg_comms_files 98 Pos := Pos + Chunk.Content'Length;
smg_comms_files 99
smg_comms_files 100 -- write counter
smg_comms_files 101 Write_U16( Msg, Pos, Chunk.Count );
smg_comms_files 102
smg_comms_files 103 -- write padding if needed
smg_comms_files 104 if Pos <= Msg'Last then
smg_comms_files 105 RNG.Get_Octets( Msg(Pos..Msg'Last) );
smg_comms_files 106 end if;
smg_comms_files 107
smg_comms_files 108 end Write_File_Transfer;
smg_comms_files 109
smg_comms_files 110 -- The opposite of Write_File_Transfer method above.
smg_comms_files 111 -- Counter will contain the message counter
smg_comms_files 112 -- Chunk will contain the chunk counter, filename and content
smg_comms_files 113 procedure Read_File_Transfer( Msg : in Raw_Types.Serpent_Msg;
smg_comms_files 114 Chunk : out File_Chunk) is
smg_comms_files 115 Pos: Integer := Msg'First;
smg_comms_files 116 U16: Interfaces.Unsigned_16;
smg_comms_files 117 S_Name, E_Name: Integer; --start/end for filename in Msg
smg_comms_files 118 S_Len: Text_Len; -- length of filename (needed as Text_Len anyway)
smg_comms_files 119 S_Content, E_Content: Integer; --start/end for content in Msg
smg_comms_files 120 Content_Len: text_Len; -- length of content (needed as Text_Len anyway)
smg_comms_files 121 begin
smg_comms_files 122 -- read and check type ID
smg_comms_files 123 if Msg(Pos) /= File_Transfer_S_Type then
smg_comms_files 124 raise Invalid_Msg;
smg_comms_files 125 end if;
smg_comms_files 126 Pos := Pos + 1;
smg_comms_files 127
smg_comms_files 128 -- read filename size
smg_comms_files 129 Read_U16( Msg, Pos, U16 );
smg_comms_files 130
smg_comms_files 131 -- check for overflow and underflow; filename size >= 1
smg_comms_files 132 if Pos + Integer(U16) - 2 > Msg'Last or
smg_comms_files 133 U16 < 3 then
smg_comms_files 134 raise Invalid_Msg;
smg_comms_files 135 end if;
smg_comms_files 136 U16 := U16 - 2;
smg_comms_files 137 S_Len := Text_Len(U16);
smg_comms_files 138
smg_comms_files 139 -- set start + end for reading filename later, when ready
smg_comms_files 140 S_Name := Pos;
smg_comms_files 141 E_Name := Pos + Integer(U16)-1;
smg_comms_files 142 Pos := Pos + S_Len;
smg_comms_files 143
smg_comms_files 144 -- read size of content
smg_comms_files 145 Read_U16( Msg, Pos, U16 );
smg_comms_files 146 -- check for overflow and underflow; content >=1; counter =2 octets
smg_comms_files 147 if Pos + Integer(U16) - 1 > Msg'Last or
smg_comms_files 148 U16 < 3 then
smg_comms_files 149 raise Invalid_msg;
smg_comms_files 150 end if;
smg_comms_files 151 U16 := U16 - 2;
smg_comms_files 152 Content_Len := Text_Len(U16);
smg_comms_files 153 -- set start and end for reading content later, when ready
smg_comms_files 154 S_Content := Pos;
smg_comms_files 155 E_Content := Pos + Integer(U16) - 1;
smg_comms_files 156 Pos := Pos + Content_Len;
smg_comms_files 157
smg_comms_files 158 -- read counter
smg_comms_files 159 Read_U16( Msg, Pos, U16 );
smg_comms_files 160 -- check chunking validity i.e. if counter>0 then no padding
smg_comms_files 161 if U16 /= 0 and Pos /= Msg'Last then
smg_comms_files 162 raise Invalid_Msg;
smg_comms_files 163 end if;
smg_comms_files 164
smg_comms_files 165 -- create File_Chunk structure and fill it with data from Msg
smg_comms_files 166 declare
smg_comms_files 167 FC : File_Chunk( Len => Content_Len,
smg_comms_files 168 Count => U16,
smg_comms_files 169 Name_Len => S_Len);
smg_comms_files 170 begin
smg_comms_files 171 -- read from Msg
smg_comms_files 172 FC.Content := Msg( S_Content..E_Content );
smg_comms_files 173 Octets_To_String( Msg( S_Name..E_Name ), FC.Filename);
smg_comms_files 174 -- copy to output var
smg_comms_files 175 Chunk := FC;
smg_comms_files 176 end;
smg_comms_files 177
smg_comms_files 178 end Read_File_Transfer;
smg_comms_files 179
smg_comms_files 180 ---- File Requests ----
smg_comms_files 181 procedure Write_File_Request( FR : in Filenames;
smg_comms_files 182 Counter : in Interfaces.Unsigned_16;
smg_comms_files 183 Msg : out Raw_Types.Serpent_Msg;
smg_comms_files 184 Written : out Natural) is
smg_comms_files 185 Pos : Integer := Msg'First;
smg_comms_files 186 Max_Pos: Integer := Msg'Last - 2; -- 2 octets at end for counter
smg_comms_files 187 Text_Sz: Integer;
smg_comms_files 188 Max_Sz : Integer;
smg_comms_files 189 begin
smg_comms_files 190 -- write ID for File Request type
smg_comms_files 191 Msg( Pos ) := File_Req_S_Type;
smg_comms_files 192 Pos := Pos + 1;
smg_comms_files 193
smg_comms_files 194 -- write Text size: filenames + separators
smg_comms_files 195 -- consider fewer filenames if they don't ALL fit
smg_comms_files 196 -- 2 octets are taken by size itself
smg_comms_files 197 Max_Sz := Max_Pos - Pos - 1;
smg_comms_files 198 Text_Sz := FR.Sz + FR.F_No - 1;
smg_comms_files 199 if Text_Sz > Max_Sz then
smg_comms_files 200 -- walk the array of filenames backwards and stop when they fit
smg_comms_files 201 Written := FR.F_No - 1;
smg_comms_files 202 -- calculate actual size written based on start of first discarded
smg_comms_files 203 -- filename and (Written -1) octets for needed separators
smg_comms_files 204 Text_Sz := Integer(FR.Starts(Written+1)) - FR.Starts'First +
smg_comms_files 205 (Written - 1);
smg_comms_files 206
smg_comms_files 207 -- loop until either fits or nothing left
smg_comms_files 208 while Written > 0 and Text_Sz > Max_Sz loop
smg_comms_files 209 Written := Written - 1;
smg_comms_files 210 Text_Sz := Integer(FR.Starts(Written+1))- FR.Starts'First +
smg_comms_files 211 (Written - 1);
smg_comms_files 212 end loop;
smg_comms_files 213 -- check that there is what to write, since nothing -> invalid message
smg_comms_files 214 if Written = 0 then
smg_comms_files 215 raise Invalid_Msg;
smg_comms_files 216 end if;
smg_comms_files 217
smg_comms_files 218 else --from if Text_Sz > Max_Sz
smg_comms_files 219 -- ALL are written
smg_comms_files 220 Written := FR.F_No;
smg_comms_files 221 end if;
smg_comms_files 222
smg_comms_files 223 -- write Text_Sz + 2 (i.e. TOTAL size)
smg_comms_files 224 if Text_Sz + 2 > Integer(Interfaces.Unsigned_16'Last) then
smg_comms_files 225 raise Invalid_Msg;
smg_comms_files 226 end if;
smg_comms_files 227
smg_comms_files 228 Write_U16( Msg, Pos, Interfaces.Unsigned_16(Text_Sz+2) );
smg_comms_files 229
smg_comms_files 230 -- write filenames separated by Sep
smg_comms_files 231 for I in 1..Written loop
smg_comms_files 232 declare
smg_comms_files 233 Start_Pos : Positive;
smg_comms_files 234 End_Pos : Positive;
smg_comms_files 235 Len : Positive;
smg_comms_files 236 begin
smg_comms_files 237 -- current start pos in FR.S
smg_comms_files 238 Start_Pos := Positive( FR.Starts( FR.Starts'First + I - 1));
smg_comms_files 239
smg_comms_files 240 -- calculate end based on start of next name or last
smg_comms_files 241 if I < FR.F_No then
smg_comms_files 242 End_Pos := Positive( FR.Starts( FR.Starts'First + I)) - 1;
smg_comms_files 243 else
smg_comms_files 244 End_Pos := FR.S'Last;
smg_comms_files 245 end if;
smg_comms_files 246
smg_comms_files 247 -- NB: this WILL fail if starting positions are not in order!
smg_comms_files 248 Len := End_Pos - Start_Pos + 1;
smg_comms_files 249 if Len <= 0 then
smg_comms_files 250 raise Invalid_Msg;
smg_comms_files 251 end if;
smg_comms_files 252
smg_comms_files 253 --write the actual filename
smg_comms_files 254 String_To_Octets( FR.S( Start_Pos..End_Pos ), Msg(Pos..Pos+Len-1) );
smg_comms_files 255 Pos := Pos + Len;
smg_comms_files 256
smg_comms_files 257 --if it's not the last one, write a separator
smg_comms_files 258 if I < Written then
smg_comms_files 259 Msg(Pos) := Sep;
smg_comms_files 260 Pos := Pos + 1;
smg_comms_files 261 end if;
smg_comms_files 262 end;
smg_comms_files 263 end loop;
smg_comms_files 264
smg_comms_files 265 -- write the message counter in little endian at all times
smg_comms_files 266 Write_U16( Msg, Pos, Counter );
smg_comms_files 267
smg_comms_files 268 -- write padding if needed
smg_comms_files 269 if Pos <= Msg'Last then
smg_comms_files 270 Rng.Get_Octets( Msg(Pos..Msg'Last) );
smg_comms_files 271 end if;
smg_comms_files 272 end Write_File_Request;
smg_comms_files 273
smg_comms_files 274 -- Reads a request for files; the opposite of Write_File_Request above
smg_comms_files 275 procedure Read_File_Request( Msg : in Raw_Types.Serpent_Msg;
smg_comms_files 276 Counter : out Interfaces.Unsigned_16;
smg_comms_files 277 FR : out Filenames) is
smg_comms_files 278 Pos : Integer := Msg'First;
smg_comms_files 279 Max_Pos : Integer := Msg'Last - 2; --at least 2 reserved for counter
smg_comms_files 280 Text_Sz : Integer;
smg_comms_files 281 Max_Sz : Integer := Max_Pos - Pos - 1; --text only i.e. w.o. size itself
smg_comms_files 282 F_No : Integer;
smg_comms_files 283 U16 : Interfaces.Unsigned_16;
smg_comms_files 284 begin
smg_comms_files 285 -- read type ID and check
smg_comms_files 286 if Msg(Pos) /= File_Req_S_Type then
smg_comms_files 287 raise Invalid_Msg;
smg_comms_files 288 end if;
smg_comms_files 289 Pos := Pos + 1;
smg_comms_files 290
smg_comms_files 291 -- read total size of filenames+separators
smg_comms_files 292 Read_U16( Msg, Pos, U16 );
smg_comms_files 293 Text_Sz := Integer(U16);
smg_comms_files 294 -- take away the 2 octets for size itself
smg_comms_files 295 Text_Sz := Text_Sz - 2;
smg_comms_files 296
smg_comms_files 297 -- check that Text_Sz is not overflowing/underflowing
smg_comms_files 298 if Text_Sz < 1 or Text_Sz > Max_Sz then
smg_comms_files 299 raise Invalid_Msg;
smg_comms_files 300 end if;
smg_comms_files 301
smg_comms_files 302 -- count first the separators to know how many filenames
smg_comms_files 303 -- NB: there is always at least 1 filename as Text_Sz > 0
smg_comms_files 304 F_No := 1;
smg_comms_files 305 for I in Pos .. Pos + Text_Sz - 1 loop
smg_comms_files 306 if Msg(I) = Sep then
smg_comms_files 307 F_No := F_No + 1;
smg_comms_files 308 end if;
smg_comms_files 309 end loop;
smg_comms_files 310
smg_comms_files 311 -- create the output structure and discard separators
smg_comms_files 312 -- text without separators should be Text_Sz - F_No + 1
smg_comms_files 313 -- (because ONLY one separator between 2 filenames allowed)
smg_comms_files 314 -- if it's not that => Invalid_Msg
smg_comms_files 315 -- F_No and Text_Sz are not overflow (earlier check + calc)
smg_comms_files 316 declare
smg_comms_files 317 F : Filenames(Text_Len(F_No), Text_Len(Text_Sz-F_No+1));
smg_comms_files 318 S_Pos : Positive;
smg_comms_files 319 Index : Positive;
smg_comms_files 320 begin
smg_comms_files 321 S_Pos := F.S'First;
smg_comms_files 322 Index := F.Starts'First;
smg_comms_files 323 F.Starts(Index) := Interfaces.Unsigned_16(S_Pos);
smg_comms_files 324
smg_comms_files 325 for I in Pos .. Pos + Text_Sz - 1 loop
smg_comms_files 326 -- copy over to F.S anything that is not separator
smg_comms_files 327 if Msg(I) /= Sep then
smg_comms_files 328 F.S( S_Pos ) := Character'Val(Msg(I));
smg_comms_files 329 S_Pos := S_Pos + 1;
smg_comms_files 330 else
smg_comms_files 331 -- if it's separator, check and if ok, add next as start
smg_comms_files 332 if I = Pos + Text_Sz or -- separator as last character is error
smg_comms_files 333 Msg(I+1) = Sep or -- 2 consecutive separators is error
smg_comms_files 334 Index >= F.Starts'Last then -- too many separators is error
smg_comms_files 335 raise Invalid_Msg;
smg_comms_files 336 else
smg_comms_files 337 Index := Index + 1;
smg_comms_files 338 F.Starts( Index ) := Interfaces.Unsigned_16(S_Pos);
smg_comms_files 339 end if;
smg_comms_files 340 end if;
smg_comms_files 341 end loop;
smg_comms_files 342
smg_comms_files 343 -- copy the whole structure to output variable
smg_comms_files 344 FR := F;
smg_comms_files 345 end;
smg_comms_files 346
smg_comms_files 347 -- read message counter now
smg_comms_files 348 Pos := Pos + Text_Sz;
smg_comms_files 349 Read_U16( Msg, Pos, Counter );
smg_comms_files 350
smg_comms_files 351 end Read_File_Request;
smg_comms_keymgm 352
smg_comms_keymgm 353 ------------------
smg_comms_keymgm 354 -- RSA Messages --
smg_comms_keymgm 355 ------------------
smg_comms_keymgm 356
smg_comms_keymgm 357 procedure Write_SKeys_RMsg( Keyset : in Serpent_Keyset;
smg_comms_keymgm 358 Counter : in Interfaces.Unsigned_16;
smg_comms_keymgm 359 Msg : out Raw_Types.RSA_Msg) is
smg_comms_keymgm 360 begin
smg_comms_keymgm 361 -- call internal write of Serpent keys with correct type ID
smg_comms_keymgm 362 Write_SKeys( Keyset, Counter, SKeys_R_Type, Msg );
smg_comms_keymgm 363 end Write_SKeys_RMsg;
smg_comms_keymgm 364
smg_comms_keymgm 365 procedure Read_SKeys_RMsg( Msg : in Raw_Types.RSA_Msg;
smg_comms_keymgm 366 Counter : out Interfaces.Unsigned_16;
smg_comms_keymgm 367 Keyset : out Serpent_Keyset) is
smg_comms_keymgm 368 begin
smg_comms_keymgm 369 -- check type id and call internal Read_SKeys if correct
smg_comms_keymgm 370 if Msg(Msg'First) /= SKeys_R_Type then
smg_comms_keymgm 371 raise Invalid_Msg;
smg_comms_keymgm 372 else
smg_comms_keymgm 373 Read_SKeys( Msg, Counter, Keyset );
smg_comms_keymgm 374 end if;
smg_comms_keymgm 375 end Read_SKeys_RMsg;
smg_comms_keymgm 376
smg_comms_keymgm 377 procedure Write_KMgm_RMsg( KMgm : in Keys_Mgm;
smg_comms_keymgm 378 Counter : in Interfaces.Unsigned_16;
smg_comms_keymgm 379 Msg : out Raw_Types.RSA_Msg) is
smg_comms_keymgm 380 begin
smg_comms_keymgm 381 -- call internal write of key mgm with correct type ID
smg_comms_keymgm 382 Write_KMgm( KMgm, Counter, Key_Mgm_R_Type, Msg );
smg_comms_keymgm 383 end Write_KMgm_RMsg;
smg_comms_keymgm 384
smg_comms_keymgm 385 procedure Read_KMgm_RMsg( Msg : in Raw_Types.RSA_Msg;
smg_comms_keymgm 386 Counter : out Interfaces.Unsigned_16;
smg_comms_keymgm 387 KMgm : out Keys_Mgm) is
smg_comms_keymgm 388 begin
smg_comms_keymgm 389 -- check type id and call internal Read_KMgm if correct
smg_comms_keymgm 390 if Msg(Msg'First) /= Key_Mgm_R_Type then
smg_comms_keymgm 391 raise Invalid_Msg;
smg_comms_keymgm 392 else
smg_comms_keymgm 393 Read_KMgm( Msg, Counter, KMgm );
smg_comms_keymgm 394 end if;
smg_comms_keymgm 395 end Read_KMgm_RMsg;
smg_comms_keymgm 396
smg_comms_files 397
smg_comms_files 398 ----------Utilities ----------
smg_comms_files 399 -- String to Octets conversion
smg_comms_files 400 procedure String_To_Octets(Str: in String; O: out Raw_Types.Octets) is
smg_comms_files 401 begin
smg_comms_files 402 Assert( Str'Length = O'Length );
smg_comms_files 403 for I in 1..Str'Length loop
smg_comms_files 404 O( O'First+I-1 ) := Character'Pos(Str(Str'First + I - 1 ));
smg_comms_files 405 end loop;
smg_comms_files 406 end String_To_Octets;
smg_comms_files 407
smg_comms_files 408 -- Octets to string conversion
smg_comms_files 409 -- NB: Str'Length has to be EQUAL to Octets'Length!
smg_comms_files 410 procedure Octets_To_String(O: in Raw_Types.Octets; Str: out String) is
smg_comms_files 411 begin
smg_comms_files 412 Assert( O'Length = Str'Length );
smg_comms_files 413 for I in 1..O'Length loop
smg_comms_files 414 Str( Str'First+I-1 ) := Character'Val(O(O'First + I - 1 ));
smg_comms_files 415 end loop;
smg_comms_files 416 end Octets_To_String;
smg_comms_files 417
smg_comms_keymgm 418 ------------------
smg_comms_keymgm 419 -- private part --
smg_comms_keymgm 420 ------------------
smg_comms_keymgm 421 procedure Cast_LE( LE: in out Raw_Types.Octets ) is
smg_comms_keymgm 422 begin
smg_comms_keymgm 423 -- flip octets ONLY if native is big endian.
smg_comms_keymgm 424 if System.Default_Bit_Order = System.High_Order_First then
smg_comms_keymgm 425 declare
smg_comms_keymgm 426 BE: constant Raw_Types.Octets := LE;
smg_comms_keymgm 427 begin
smg_comms_keymgm 428 for I in 1..LE'Length loop
smg_comms_keymgm 429 LE(LE'First+I-1) := BE(BE'Last-I+1);
smg_comms_keymgm 430 end loop;
smg_comms_keymgm 431 end;
smg_comms_keymgm 432 end if;
smg_comms_keymgm 433 -- NOTHING to do for native little endian
smg_comms_keymgm 434 end Cast_LE;
smg_comms_keymgm 435
smg_comms_keymgm 436 procedure Write_SKeys( Keyset : in Serpent_Keyset;
smg_comms_keymgm 437 Counter : in Interfaces.Unsigned_16;
smg_comms_keymgm 438 Type_ID : in Interfaces.Unsigned_8;
smg_comms_keymgm 439 Msg : out Raw_Types.Octets) is
smg_comms_skeys_s... 440 Pos : Integer := Msg'First;
smg_comms_skeys_s... 441 Check : CRC32.CRC32;
smg_comms_skeys_s... 442 K : Serpent.Key;
smg_comms_skeys_s... 443 begin
smg_comms_skeys_s... 444 -- write Type ID
smg_comms_keymgm 445 Msg(Pos) := Type_ID;
smg_comms_skeys_s... 446 Pos := Pos + 1;
smg_comms_skeys_s... 447
smg_comms_skeys_s... 448 -- write count of keys (NB: this IS 8 bits by definition)
smg_comms_skeys_s... 449 Msg(Pos) := Keyset.Keys'Length;
smg_comms_skeys_s... 450 Pos := Pos + 1;
smg_comms_skeys_s... 451
smg_comms_skeys_s... 452 -- write keys
smg_comms_skeys_s... 453 for I in Keyset.Keys'Range loop
smg_comms_skeys_s... 454 -- retrieve Key to write
smg_comms_skeys_s... 455 K := Keyset.Keys( I );
smg_comms_skeys_s... 456
smg_comms_skeys_s... 457 -- write key itself
smg_comms_skeys_s... 458 Msg(Pos..Pos+K'Length-1) := K;
smg_comms_skeys_s... 459 -- ensure little endian order in message
smg_comms_skeys_s... 460 Cast_LE(Msg(Pos..Pos+K'Length-1));
smg_comms_skeys_s... 461 Pos := Pos + K'Length;
smg_comms_skeys_s... 462
smg_comms_skeys_s... 463 -- write CRC of key
smg_comms_skeys_s... 464 Check := CRC32.CRC( K );
smg_comms_skeys_s... 465 Msg(Pos..Pos+3) := Raw_Types.Cast(Check);
smg_comms_skeys_s... 466 Cast_LE(Msg(Pos..Pos+3));
smg_comms_skeys_s... 467 Pos := Pos + 4;
smg_comms_skeys_s... 468 end loop;
smg_comms_skeys_s... 469
smg_comms_skeys_s... 470 -- write flag
smg_comms_skeys_s... 471 Msg(Pos) := Keyset.Flag;
smg_comms_skeys_s... 472 Pos := Pos + 1;
smg_comms_skeys_s... 473
smg_comms_skeys_s... 474 -- write message counter
smg_comms_files 475 Write_U16( Msg, Pos, Counter );
smg_comms_skeys_s... 476
smg_comms_skeys_s... 477 -- write padding as needed; endianness is irrelevant here
smg_comms_files 478 if Pos <= Msg'Last then
smg_comms_files 479 RNG.Get_Octets( Msg(Pos..Msg'Last) );
smg_comms_skeys_s... 480 end if;
smg_comms_skeys_s... 481
smg_comms_keymgm 482 end Write_SKeys;
smg_comms_skeys_s... 483
smg_comms_keymgm 484 procedure Read_SKeys( Msg : in Raw_Types.Octets;
smg_comms_keymgm 485 Counter : out Interfaces.Unsigned_16;
smg_comms_keymgm 486 Keyset : out Serpent_Keyset) is
smg_comms_skeys_s... 487 Pos: Integer := Msg'First;
smg_comms_skeys_s... 488 begin
smg_comms_skeys_s... 489 -- read type and check
smg_comms_keymgm 490 if Msg(Pos) = SKeys_S_Type or
smg_comms_keymgm 491 Msg(Pos) = SKeys_R_Type then
smg_comms_skeys_s... 492 Pos := Pos + 1;
smg_comms_skeys_s... 493 else
smg_comms_skeys_s... 494 raise Invalid_Msg;
smg_comms_skeys_s... 495 end if;
smg_comms_skeys_s... 496
smg_comms_skeys_s... 497 -- read count of keys and check
smg_comms_skeys_s... 498 if Msg(Pos) in Keys_Count'Range then
smg_comms_skeys_s... 499 declare
smg_comms_skeys_s... 500 N : Keys_Count := Keys_Count(Msg(Pos));
smg_comms_skeys_s... 501 KS : Serpent_Keyset(N);
smg_comms_skeys_s... 502 K : Serpent.Key;
smg_comms_skeys_s... 503 Check : CRC32.CRC32;
smg_comms_skeys_s... 504 O4 : Raw_Types.Octets_4;
smg_comms_skeys_s... 505 begin
smg_comms_skeys_s... 506 Pos := Pos + 1;
smg_comms_skeys_s... 507 --read keys and check crc for each
smg_comms_skeys_s... 508 for I in 1 .. N loop
smg_comms_skeys_s... 509 -- read key and advance pos
smg_comms_skeys_s... 510 K := Msg(Pos..Pos+K'Length-1);
smg_comms_skeys_s... 511 Cast_LE(K);
smg_comms_skeys_s... 512 Pos := Pos + K'Length;
smg_comms_skeys_s... 513 -- read crc and compare to crc32(key)
smg_comms_skeys_s... 514 O4 := Msg(Pos..Pos+3);
smg_comms_skeys_s... 515 Cast_LE(O4);
smg_comms_skeys_s... 516 Check := Raw_Types.Cast(O4);
smg_comms_skeys_s... 517 Pos := Pos + 4;
smg_comms_skeys_s... 518 if Check /= CRC32.CRC(K) then
smg_comms_skeys_s... 519 raise Invalid_Msg;
smg_comms_skeys_s... 520 end if;
smg_comms_skeys_s... 521 -- if it got here, key is fine so add to set
smg_comms_skeys_s... 522 KS.Keys(KS.Keys'First + I -1) := K;
smg_comms_skeys_s... 523 end loop;
smg_comms_skeys_s... 524 -- read and set flag
smg_comms_skeys_s... 525 KS.Flag := Msg(Pos);
smg_comms_skeys_s... 526 Pos := Pos + 1;
smg_comms_skeys_s... 527 -- read and set message counter
smg_comms_files 528 Read_U16( Msg, Pos, Counter );
smg_comms_skeys_s... 529 -- rest of message is padding so it's ignored
smg_comms_skeys_s... 530 -- copy keyset to output variable
smg_comms_skeys_s... 531 Keyset := KS;
smg_comms_skeys_s... 532 end;
smg_comms_skeys_s... 533 else
smg_comms_skeys_s... 534 raise Invalid_Msg;
smg_comms_skeys_s... 535 end if;
smg_comms_keymgm 536 end Read_SKeys;
smg_comms_skeys_s... 537
smg_comms_keymgm 538 -- writes given key management structure to the given octets array
smg_comms_keymgm 539 procedure Write_KMgm( KMgm : in Keys_Mgm;
smg_comms_keymgm 540 Counter : in Interfaces.Unsigned_16;
smg_comms_keymgm 541 Type_ID : in Interfaces.Unsigned_8;
smg_comms_keymgm 542 Msg : out Raw_Types.Octets) is
smg_comms_keymgm 543 Pos : Integer := Msg'First;
smg_comms_skeys_s... 544 begin
smg_comms_keymgm 545 -- write given type id
smg_comms_keymgm 546 Msg(Pos) := Type_ID;
smg_comms_keymgm 547 Pos := Pos + 1;
smg_comms_keymgm 548
smg_comms_keymgm 549 -- write count of server keys requested
smg_comms_keymgm 550 Msg(Pos) := KMgm.N_Server;
smg_comms_keymgm 551 Pos := Pos + 1;
smg_comms_keymgm 552
smg_comms_keymgm 553 -- write count of client keys requested
smg_comms_keymgm 554 Msg(Pos) := KMgm.N_Client;
smg_comms_keymgm 555 Pos := Pos + 1;
smg_comms_keymgm 556
smg_comms_keymgm 557 -- write id of key preferred for further inbound Serpent messages
smg_comms_keymgm 558 Msg(Pos) := KMgm.Key_ID;
smg_comms_keymgm 559 Pos := Pos + 1;
smg_comms_keymgm 560
smg_comms_keymgm 561 -- write count of burnt keys in this message
smg_comms_keymgm 562 Msg(Pos..Pos) := Cast( KMgm.N_Burnt );
smg_comms_keymgm 563 Pos := Pos + 1;
smg_comms_keymgm 564
smg_comms_keymgm 565 -- if there are any burnt keys, write their ids
smg_comms_keymgm 566 if KMgm.N_Burnt > 0 then
smg_comms_keymgm 567 Msg( Pos .. Pos + KMgm.Burnt'Length - 1 ) := KMgm.Burnt;
smg_comms_keymgm 568 Pos := Pos + KMgm.Burnt'Length;
smg_comms_skeys_s... 569 end if;
smg_comms_keymgm 570
smg_comms_keymgm 571 -- write the message count
smg_comms_files 572 Write_U16( Msg, Pos, Counter );
smg_comms_keymgm 573
smg_comms_keymgm 574 -- pad with random octets until the end of Msg
smg_comms_files 575 if Pos <= Msg'Last then
smg_comms_files 576 RNG.Get_Octets( Msg(Pos..Msg'Last) );
smg_comms_files 577 end if;
smg_comms_keymgm 578
smg_comms_keymgm 579 end Write_KMgm;
smg_comms_keymgm 580
smg_comms_keymgm 581 -- attempts to read from the given array of octets a key management structure
smg_comms_keymgm 582 procedure Read_KMgm( Msg : in Raw_Types.Octets;
smg_comms_keymgm 583 Counter : out Interfaces.Unsigned_16;
smg_comms_keymgm 584 KMgm : out Keys_Mgm) is
smg_comms_keymgm 585 Pos : Integer := Msg'First;
smg_comms_keymgm 586 Burnt_Pos : Integer := Msg'First + 4;
smg_comms_keymgm 587 begin
smg_comms_keymgm 588 -- read type and check
smg_comms_keymgm 589 if Msg(Pos) = Key_Mgm_S_Type or
smg_comms_keymgm 590 Msg(Pos) = Key_Mgm_R_Type then
smg_comms_keymgm 591 Pos := Pos + 1;
smg_comms_keymgm 592 else
smg_comms_keymgm 593 raise Invalid_Msg;
smg_comms_keymgm 594 end if;
smg_comms_keymgm 595
smg_comms_keymgm 596 -- read the count of burnt keys and check
smg_comms_keymgm 597 -- NB: Burnt_Pos IS in range of Counter_8bits since it's an octet
smg_comms_keymgm 598 declare
smg_comms_keymgm 599 N_Burnt : Counter_8bits := Counter_8bits(Msg(Burnt_Pos));
smg_comms_keymgm 600 Mgm : Keys_Mgm(N_Burnt);
smg_comms_keymgm 601 begin
smg_comms_keymgm 602 -- read count of server keys requested
smg_comms_keymgm 603 Mgm.N_Server := Msg(Pos);
smg_comms_keymgm 604 Pos := Pos + 1;
smg_comms_keymgm 605
smg_comms_keymgm 606 -- read count of client keys requested
smg_comms_keymgm 607 Mgm.N_Client := Msg(Pos);
smg_comms_keymgm 608 Pos := Pos + 1;
smg_comms_keymgm 609
smg_comms_keymgm 610 -- read ID of Serpent key preferred for further inbound messages
smg_comms_keymgm 611 Mgm.Key_ID := Msg(Pos);
smg_comms_keymgm 612 Pos := Pos + 2; --skip the count of burnt keys as it's read already
smg_comms_keymgm 613
smg_comms_keymgm 614 -- read ids of burnt keys, if any
smg_comms_keymgm 615 if N_Burnt > 0 then
smg_comms_keymgm 616 Mgm.Burnt := Msg(Pos..Pos+N_Burnt-1);
smg_comms_keymgm 617 Pos := Pos + N_Burnt;
smg_comms_keymgm 618 end if;
smg_comms_keymgm 619
smg_comms_keymgm 620 -- read and set message counter
smg_comms_files 621 Read_U16( Msg, Pos, Counter );
smg_comms_keymgm 622 -- rest of message is padding so it's ignored
smg_comms_keymgm 623 -- copy the keys mgm structure to output param
smg_comms_keymgm 624 KMgm := Mgm;
smg_comms_keymgm 625 end;
smg_comms_keymgm 626 end Read_KMgm;
smg_comms_keymgm 627
smg_comms_files 628 -- Write a 16 bits value to Octets at Pos; Pos increases by 2.
smg_comms_files 629 procedure Write_U16( Msg: in out Raw_Types.Octets;
smg_comms_files 630 Pos: in out Natural;
smg_comms_files 631 U16: in Interfaces.Unsigned_16) is
smg_comms_files 632 begin
smg_comms_files 633 Msg(Pos..Pos+1) := Raw_Types.Cast(U16);
smg_comms_files 634 Cast_LE(Msg(Pos..Pos+1));
smg_comms_files 635 Pos := Pos + 2;
smg_comms_files 636 end Write_U16;
smg_comms_files 637
smg_comms_files 638 -- Read a 16-bits values from Octets from Pos; Pos increases by 2.
smg_comms_files 639 procedure Read_U16( Msg: in Raw_Types.Octets;
smg_comms_files 640 Pos: in out Natural;
smg_comms_files 641 U16: out Interfaces.Unsigned_16) is
smg_comms_files 642 O2 : Raw_Types.Octets_2;
smg_comms_files 643 begin
smg_comms_files 644 O2 := Msg(Pos..Pos+1);
smg_comms_files 645 Cast_LE(O2);
smg_comms_files 646 U16 := Raw_Types.Cast(O2);
smg_comms_files 647 Pos := Pos + 2;
smg_comms_files 648 end Read_U16;
smg_comms_skeys_s... 649
smg_comms_skeys_s... 650 end Messages;