C ++ Crypto: Bölüm 2- HMAC
Modern Crypto kitaplıklarını araştırmak.
İyi bir şey bulamadım.
Muhtemelen bunu yanlış yaptığımı biliyorum, bu yüzden burada çalışın. Birbiri üzerine inşa edilen dört yapı için dört farklı inceleme olacak:
- Hashing
- Hashed Anahtar
- Şifre Anahtarı
- Tuzlu Meydan Okuma Yanıtı
Bu sorularda sunulan veri yapıları ve uygulama, RFC2104'e ve kod projesiyle ilgili bu gönderiye dayanmaktadır .
Bu inceleme, HMAC'ın bir uygulaması içindir. Bu, bir Anahtar kullanarak parolayı karma oluşturma tekniğidir.
Kullanım Örneği:
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
Yanıtlar
Düz sindirimlerin ve HMAC'lerin sonuçlarını saklamak için aynı türü kullanmaktan kaçının
Bir HMAC'yi sade bir özetle karşılaştıramazsınız (veya en azından asla karşılaştıramazsınız). Tip sistemi bu potansiyel hatayı yakalayabilseydi iyi olurdu. DigestStore<Hash>Hem sade özler hem de HMAC'lar için kullanılan bir sınıfa sahip olmak yerine, sadece kendi sonuçlarını doğrudan alır Digest<Hash>ve HMAC<Hash>her biri kendi sonucunu saklar.
HMAC'a birden çok adımda veri eklemeye izin verin
Bölüm 1 incelemesinde belirtildiği gibi, HMAC'a eklenecek birden çok, bitişik olmayan veri parçasının eklenmesi alışılmadık bir durum değildir, bu nedenle add()HMAC'ı güncelleyebilecek bir üye işlevine sahip olun. Bu, HMAC'ın oluşturulmasını üç bölüme ayırmak anlamına gelir:
- Anahtar malzeme, yapıcının bir parçası olarak hazırlanır
- Mesaj hash'e tek seferde veya birden çok işlev çağrısı kullanılarak eklenir
- Nihai değer hesaplanır
Sınıfı şu şekilde yapılandırırım:
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();
}
};
finish()Birden fazla aranmayı önlemek için bir yol da eklemek isteyebilirsiniz .
Güvenli olmayan işlemlerden kaçının
Kendi sözlerin:
İyi tip güvenliği ve güzel temiz C ++ arayüzleri ve teknikleri kullanmak yerine C'nin etrafındaki berbat sarmalayıcılar olan bu kötü yazılmış C ++ (bu yüzden bu hack'e başladım) projelerini okumaktan nefret ediyorum.
İyi bir güvenlik istiyorsun, ama aynı zamanda genel olarak iyi bir güvenlik istediğini düşünüyorum. Güvenli olmayan işlevler oluşturmak bu amaca aykırıdır. Bir karmanın sonuçlarını bir Digestnesnede depoluyorsanız ve depoladığı verilere bir sabit referans almanın bir yolu varsa, o zaman bir hashUnsafe()işleve ihtiyacınız yoktur .