mac.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. /**
  2. * Copyright (C) 2011 Anders Sundman <anders@4zm.org>
  3. *
  4. * This file is part of mfterm.
  5. *
  6. * mfterm is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. * mfterm is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. * You should have received a copy of the GNU General Public License
  15. * along with mfterm. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <openssl/des.h>
  18. #include <string.h>
  19. #include "util.h"
  20. #include "mac.h"
  21. #include "tag.h"
  22. // The DES MAC key in use
  23. unsigned char current_mac_key[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  24. /**
  25. * Compute a DES MAC, use DES in CBC mode. Key and output should be 8
  26. * bytes. The length specifies the length of the input in bytes. It
  27. * will be zero padded to 8 byte alignment if required.
  28. */
  29. int compute_mac(const unsigned char* input,
  30. unsigned char* output,
  31. const unsigned char* key,
  32. long length) {
  33. DES_cblock des_key =
  34. { key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7] };
  35. // todo zeropad input if required
  36. const unsigned char* padded_input = input;
  37. // Generate a key schedule. Don't be picky, allow bad keys.
  38. DES_key_schedule schedule;
  39. DES_set_key_unchecked(&des_key, &schedule);
  40. // IV is all zeroes
  41. unsigned char ivec[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  42. // Compute the DES in CBC
  43. DES_ncbc_encrypt(padded_input, output, length, &schedule, &ivec, 1);
  44. // Move up and truncate (we only want 8 bytes)
  45. for (int i = 0; i < 8; ++i)
  46. output[i] = output[length - 8 + i];
  47. for (int i = 8; i < length; ++i)
  48. output[i] = 0;
  49. return 0;
  50. }
  51. /**
  52. * Compute the MAC of a given block with the specified 8 byte
  53. * key. Return a 8 byte MAC value.
  54. *
  55. * The input to MAC algo [ 4 serial | 14 data | 6 0-pad ]
  56. *
  57. * If update is * nonzero, the mac of the current tag is updated. If
  58. * not, the MAC is simply printed.
  59. */
  60. unsigned char* compute_block_mac(unsigned int block,
  61. const unsigned char* key,
  62. int update) {
  63. static unsigned char output[8];
  64. // Input to MAC algo [ 4 serial | 14 data | 6 0-pad ]
  65. unsigned char input[24];
  66. memcpy(&input, current_tag.amb[0].mbm.abtUID, 4);
  67. memcpy(&input[4], current_tag.amb[block].mbd.abtData, 14);
  68. memset(&input[18], 0, 6);
  69. int res = 0;
  70. res = compute_mac(input, output, key, 24);
  71. // Ret null on error
  72. if (res != 0) return NULL;
  73. // Should the new MAC be written back?
  74. if (update) {
  75. memcpy(&current_tag.amb[block].mbd.abtData[14], output, 2);
  76. }
  77. return output;
  78. }