crypto.cc 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include "crypto.h"
  15. #include <iostream>
  16. #include <iomanip>
  17. #include "crypto_botan.h"
  18. #include <botan/botan.h>
  19. #include <botan/hmac.h>
  20. #include <botan/types.h>
  21. #include <dns/buffer.h>
  22. #include <dns/name.h>
  23. #include <dns/tsigkey.h>
  24. #include <dns/util/base64.h>
  25. #include <string>
  26. using namespace Botan;
  27. using namespace std;
  28. using namespace isc::dns;
  29. namespace {
  30. HashFunction* getHash(const Name& hash_name) {
  31. if (hash_name == TSIGKey::HMACMD5_NAME()) {
  32. return get_hash("MD5");
  33. } else if (hash_name == TSIGKey::HMACSHA1_NAME()) {
  34. return get_hash("SHA-1");
  35. } else if (hash_name == TSIGKey::HMACSHA256_NAME()) {
  36. return get_hash("SHA-256");
  37. } else {
  38. isc_throw(isc::crypto::UnsupportedAlgorithm,
  39. "Unknown Hash type " + hash_name.toText());
  40. }
  41. }
  42. // Library needs to have been inited during the entire program
  43. // should we make this a singleton? (for hsm we'll need more
  44. // initialization, and dynamic loading)
  45. LibraryInitializer init;
  46. } // local namespace
  47. namespace isc {
  48. namespace crypto {
  49. void
  50. signHMAC(const OutputBuffer& data, TSIGKey key,
  51. isc::dns::OutputBuffer& result)
  52. {
  53. // get algorithm from key, then 'translate' to Botan-specific algo
  54. HashFunction* hash = getHash(key.getAlgorithmName());
  55. HMAC::HMAC hmac(hash);
  56. // Take the 'secret' from the key
  57. try {
  58. hmac.set_key(static_cast<const byte*>(key.getSecret()),
  59. key.getSecretLength());
  60. } catch (Invalid_Key_Length ikl) {
  61. isc_throw(BadKey, ikl.what());
  62. }
  63. // update the data from whatever we get (probably as a buffer)
  64. hmac.update(static_cast<const byte*>(data.getData()),
  65. data.getLength());
  66. // And generate the mac
  67. SecureVector<byte> b_result(hmac.final());
  68. // write mac to result
  69. result.writeData(b_result.begin(), b_result.size());
  70. }
  71. bool
  72. verifyHMAC(const OutputBuffer& data, TSIGKey key,
  73. const isc::dns::OutputBuffer& result)
  74. {
  75. HashFunction* hash = getHash(key.getAlgorithmName());
  76. HMAC::HMAC hmac(hash);
  77. try {
  78. hmac.set_key(static_cast<const byte*>(key.getSecret()), key.getSecretLength());
  79. } catch (Invalid_Key_Length ikl) {
  80. isc_throw(BadKey, ikl.what());
  81. }
  82. hmac.update(static_cast<const byte*>(data.getData()), data.getLength());
  83. return hmac.verify_mac(static_cast<const byte*>(result.getData()), result.getLength());
  84. }
  85. isc::dns::TSIGKey
  86. TSIGKeyFromString(const std::string& str) {
  87. size_t pos = str.find(':');
  88. if (pos == 0 || pos == str.npos) {
  89. // error
  90. isc_throw(InvalidParameter, "Invalid TSIG key string");
  91. }
  92. try {
  93. Name key_name(str.substr(0, pos));
  94. Name algo_name("hmac-md5.sig-alg.reg.int");
  95. // optional algorithm part
  96. size_t pos2 = str.find(':', pos+1);
  97. if (pos2 != str.npos) {
  98. if (pos2 == pos + 1) {
  99. isc_throw(InvalidParameter, "Invalid TSIG key string");
  100. }
  101. algo_name = Name(str.substr(pos2+1));
  102. } else {
  103. pos2 = str.size() - pos;
  104. }
  105. std::string secret_str = str.substr(pos + 1, pos2 - pos - 1);
  106. vector<uint8_t> secret;
  107. decodeBase64(secret_str, secret);
  108. unsigned char secret_b[secret.size()];
  109. for (size_t i=0; i < secret.size(); ++i) {
  110. secret_b[i] = secret[i];
  111. }
  112. return isc::dns::TSIGKey(key_name, algo_name, secret_b, secret.size());
  113. } catch (Exception e) {
  114. // 'reduce' the several types of exceptions name parsing and
  115. // Base64 decoding can throw to just the InvalidParameter
  116. isc_throw(InvalidParameter, e.what());
  117. }
  118. }
  119. std::string
  120. TSIGKeyToString(const isc::dns::TSIGKey& key) {
  121. const uint8_t* secret_b = static_cast<const uint8_t*>(key.getSecret());
  122. vector<uint8_t> secret_v;
  123. for (size_t i=0; i < key.getSecretLength(); ++i) {
  124. secret_v.push_back(secret_b[i]);
  125. }
  126. std::string secret_str = encodeBase64(secret_v);
  127. return key.getKeyName().toText() + ":" + secret_str + ":" + key.getAlgorithmName().toText();
  128. }
  129. } // namespace crypto
  130. } // namespace isc