C ++ Crypto: Bagian 2- HMAC
Mencari perpustakaan Crypto modern.
Tidak dapat menemukan sesuatu yang bagus.
Saya tahu saya mungkin melakukan ini semua salah jadi bekerjalah dengan saya di sini. Akan ada empat ulasan berbeda untuk empat struktur yang dibangun di atas satu sama lain:
- Hashing
- Kunci Hashed
- Kunci Sandi
- Respon Tantangan Asin
Struktur data dan implementasi yang disajikan dalam pertanyaan-pertanyaan ini didasarkan pada RFC2104 dan posting ini pada codeproject .
Review ini untuk implementasi HMAC. Ini adalah teknik untuk mencirikan kata sandi menggunakan Kunci.
Contoh Penggunaan:
Digest<HMac<Sha1>> digest;
HMac<Sha1> hasher;
hasher.hash("This is the Key", "This is the message", digest);
hmac.h
#ifndef THORS_ANVIL_CRYPTO_HMAC_H
#define THORS_ANVIL_CRYPTO_HMAC_H
#include "hash.h"
// HMAC: Keyed-Hashing for Message Authentication RFC-2104
namespace ThorsAnvil::Crypto
{
// Look in hash.h for good examples of THash
// ThorsAnvil::Crypto::Sha1
template<typename THash>
struct HMac
{
static constexpr std::size_t digestSize = THash::digestSize;
using Hash = THash;
using DigestStore = typename Hash::DigestStore;
void hash(std::string_view key, std::string_view message, DigestStore& digest)
{
Hash hasher;
enum { BLOCK_SIZE = 64 };
/* STEP 1 */
std::array<Byte, BLOCK_SIZE> SHA1_Key{'\x00'};
if (key.size() > BLOCK_SIZE)
{
hasher.hashUnsafe(key, &SHA1_Key[0]);
}
else
{
std::copy(std::begin(key), std::end(key), &SHA1_Key[0]);
}
/* STEP 2 */
std::string ipad;
std::string opad;
ipad.reserve(BLOCK_SIZE + std::size(message));
opad.reserve(BLOCK_SIZE + digestSize);
ipad.resize(BLOCK_SIZE, '\x36');
opad.resize(BLOCK_SIZE, '\x5c');
for (int i=0; i< BLOCK_SIZE; i++)
{
ipad[i] ^= SHA1_Key[i];
opad[i] ^= SHA1_Key[i];
}
/* STEP 3 */
std::copy(std::begin(message), std::end(message), std::back_inserter(ipad));
/* STEP 4 */
opad.resize(BLOCK_SIZE + digestSize);
hasher.hashUnsafe(ipad, reinterpret_cast<Byte*>(&opad[BLOCK_SIZE]));
/* STEP 5 */
// Moved XOR of opad to STEP 2
/* STEP 6 */
// Don't need to copy the hash of ipad onto opad as we hashed
// into the correct destination.
/*STEP 7 */
hasher.hash(opad, digest);
}
};
}
#endif
Jawaban
Hindari menggunakan jenis yang sama untuk menyimpan hasil pencernaan biasa dan HMAC
Anda tidak dapat (atau setidaknya tidak pernah dapat) membandingkan HMAC dengan intisari biasa. Jadi akan lebih baik jika sistem tipe bisa menangkap potensi kesalahan itu. Alih-alih memiliki DigestStore<Hash>kelas yang digunakan baik untuk digest biasa dan HMAC, saya hanya akan memiliki Digest<Hash>dan HMAC<Hash>masing - masing menyimpan hasilnya sendiri secara langsung.
Izinkan menambahkan data ke HMAC dalam beberapa langkah
Seperti disebutkan dalam ulasan untuk bagian 1, tidak jarang harus menambahkan beberapa bagian data yang tidak bersebelahan untuk ditambahkan ke HMAC, jadi miliki fungsi anggota add()yang dapat memperbarui HMAC. Ini berarti membagi pembuatan HMAC menjadi tiga bagian:
- Materi kunci disiapkan sebagai bagian dari konstruktor
- Pesan ditambahkan ke hash, baik dalam sekali jalan atau menggunakan beberapa panggilan fungsi
- Nilai akhir dihitung
Saya akan menyusun kelas seperti ini:
template<typename Hash>
class HMAC {
Digest<Hash> outer_digest;
Digest<Hash> inner_digest;
public:
HMAC(std::string_view key) {
// Add key XOR opad to outer_digest
// Add key XOR ipad to inner_digest
}
// Convenience constructor to do a one-shot HMAC creation
HMAC(std::string_view key, std::string_view message): HMAC(key) {
add(message);
finish();
}
void add(std::string_view message) {
// Add message to inner_digest
}
void finish() {
// Finish inner_digest, add it to outer_digest
// Finish outer_digest
}
// Something to get the bits out
const auto &get() {
return outer_digest.get();
}
};
Anda mungkin juga ingin menambahkan beberapa cara untuk mencegah finish()agar tidak dipanggil lebih dari sekali.
Hindari pengoperasian yang tidak aman
Kata-katamu sendiri:
Saya hanya benci membaca C ++ yang ditulis dengan buruk ini (itulah sebabnya saya memulai peretasan ini) proyek yang merupakan pembungkus jelek di sekitar C daripada menggunakan keamanan tipe yang baik dan antarmuka dan teknik C ++ yang bersih dan bagus.
Anda menginginkan keamanan tipe yang baik, tetapi menurut saya Anda juga menginginkan keamanan yang baik secara umum. Membuat fungsi yang tidak aman bertentangan dengan tujuan itu. Jika Anda menyimpan hasil hash dalam sebuah Digestobjek, dan memiliki cara untuk mendapatkan referensi const ke data yang disimpannya, maka Anda tidak memerlukan hashUnsafe()fungsi.