読者です 読者をやめる 読者になる 読者になる

堕(惰)プログラマ開発記録

タイトル変えようかなとも思ってるけれど,思い浮かばない

HMAC-SHA1 powered by OpenSSL

C++

C++で自作HMAC-SHA1を書くのに挫折*1
代わりにSSLで依存しているOpenSSLを使用することにしました。

OpenSSLでSHA-1するコードは

std::string sha1(const std::string &data)
{
  //用意
  SHA_CTX encoder;
  unsigned char result[SHA_DIGEST_LENGTH];

  //計算
  SHA1_Init(&encoder);
  SHA1_Update(&encoder, data.c_str(), data.length());
  SHA1_Final(result, &encoder);
  result[SHA_DIGEST_LENGTH] = 0x00;

  return static_cast<std::string>((char*)result);  
}

これで出来ました。
結果も合ってました。
関数をダラダラ書くより、とっても簡単だったよ…

HMAC-SHA1SHA1もセットで一気にやってくれます。
SHA1より長くなりましたが、自分で実装する手間を考えたらとても楽。

std::string hmac_sha1(const std::string& key,const std::string& data)
{
  unsigned char res[SHA_DIGEST_LENGTH + 1];
  size_t  reslen;
  size_t  keylen = key.length();
  size_t  datalen = data.length();

  //これで計算
  HMAC (EVP_sha1(), (const unsigned char*)key.c_str(), keylen, (const unsigned char*)data.c_str(), datalen, res, &reslen);

  std::string result((char*)res);
  result.erase(reslen);

  return result;
}

ついでにOAuth用のsignatureを作るのが目的だったので、
Base64エンコードもしてしまいました。
エンコードもデコードもやってくれる…。凄いですね、OpenSSL。

std::string encode(const std::string& data)
{
  //フィルタ作成
  BIO *encoder = BIO_new(BIO_f_base64());
  BIO *bmem = BIO_new(BIO_s_mem());
  encoder = BIO_push(encoder,bmem);
  BIO_write(encoder,data.c_str(),data.length());
  BIO_flush(encoder);

  //結果をここに
  BUF_MEM *bptr;
  BIO_get_mem_ptr(encoder,&bptr);
  
  //charに移行処理
  char *buff = (char *)malloc(bptr->length);
  memcpy(buff, bptr->data, bptr->length-1);
  buff[bptr->length-1] = 0;
  
  //クリア
  BIO_free_all(encoder);

  return static_cast<std::string>(buff);
}
std::string decode(const std::string& data)
{
  //バッファ領域の確保。デコードデータはエンコードデータよりも小さい。
  const int length = data.length();
  char *buff = (char*)malloc(length);
  memset(buff,0x00,length);

  //フィルタ作成
  BIO *decoder = BIO_new(BIO_f_base64());
  BIO *bmem = BIO_new_mem_buf((char*)data.c_str(),length);
  bmem = BIO_push(decoder,bmem);
  BIO_read(bmem,buff,length);

  BIO_free_all(bmem);

  return static_cast<std::string>(buff);
}

BIOとかいうのを使うみたい。
さらに、これを使うとBase64以外も簡単にできるみたい。

*1:自分の技術が向上したらまた挑戦してみたいですが