Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ISC Open Source Projects
Kea
Commits
e74f6d5e
Commit
e74f6d5e
authored
Apr 20, 2011
by
Jelte Jansen
Browse files
[trac781] make a singleton entry point, moved hmac into own source file
parent
f137e0fa
Changes
7
Hide whitespace changes
Inline
Side-by-side
src/lib/crypto/Makefile.am
View file @
e74f6d5e
...
...
@@ -9,3 +9,4 @@ CLEANFILES = *.gcno *.gcda
lib_LTLIBRARIES
=
libb10crypto.la
libb10crypto_la_SOURCES
=
crypto.h crypto.cc
libb10crypto_la_SOURCES
+=
crypto_hmac.h crypto_hmac.cc
src/lib/crypto/crypto.cc
View file @
e74f6d5e
...
...
@@ -27,32 +27,11 @@
#include
<boost/scoped_ptr.hpp>
#include
<iostream>
using
namespace
std
;
using
namespace
isc
::
dns
;
namespace
{
const
char
*
getBotanHashAlgorithmName
(
isc
::
crypto
::
HMAC
::
HashAlgorithm
algorithm
)
{
switch
(
algorithm
)
{
case
isc
::
crypto
::
HMAC
::
MD5
:
return
(
"MD5"
);
break
;
case
isc
::
crypto
::
HMAC
::
SHA1
:
return
(
"SHA-1"
);
break
;
case
isc
::
crypto
::
HMAC
::
SHA256
:
return
(
"SHA-256"
);
break
;
case
isc
::
crypto
::
HMAC
::
UNKNOWN
:
return
(
"Unknown"
);
break
;
}
// compiler should have prevented us to reach this, since we have
// no default. But we need a return value anyway
return
(
"Unknown"
);
}
}
// local namespace
namespace
isc
{
namespace
crypto
{
...
...
@@ -67,144 +46,39 @@ private:
Botan
::
LibraryInitializer
_botan_init
;
};
Crypto
::
Crypto
()
{
try
{
impl_
=
new
CryptoImpl
();
}
catch
(
const
Botan
::
Exception
&
ex
)
{
isc_throw
(
InitializationError
,
ex
.
what
());
}
}
Crypto
::~
Crypto
()
{
delete
impl_
;
}
class
HMACImpl
{
public:
explicit
HMACImpl
(
const
void
*
secret
,
size_t
secret_len
,
const
HMAC
::
HashAlgorithm
hash_algorithm
)
{
Botan
::
HashFunction
*
hash
;
try
{
hash
=
Botan
::
get_hash
(
getBotanHashAlgorithmName
(
hash_algorithm
));
}
catch
(
const
Botan
::
Algorithm_Not_Found
&
)
{
isc_throw
(
isc
::
crypto
::
UnsupportedAlgorithm
,
"Unknown hash algorithm: "
+
hash_algorithm
);
}
hmac_
.
reset
(
new
Botan
::
HMAC
::
HMAC
(
hash
));
// If the key length is larger than the block size, we hash the
// key itself first.
try
{
if
(
secret_len
>
hash
->
HASH_BLOCK_SIZE
)
{
Botan
::
SecureVector
<
Botan
::
byte
>
hashed_key
=
hash
->
process
(
static_cast
<
const
Botan
::
byte
*>
(
secret
),
secret_len
);
hmac_
->
set_key
(
hashed_key
.
begin
(),
hashed_key
.
size
());
}
else
{
hmac_
->
set_key
(
static_cast
<
const
Botan
::
byte
*>
(
secret
),
secret_len
);
}
}
catch
(
const
Botan
::
Invalid_Key_Length
&
ikl
)
{
isc_throw
(
BadKey
,
ikl
.
what
());
}
}
~
HMACImpl
()
{
}
size_t
getOutputLength
()
const
{
return
(
hmac_
->
OUTPUT_LENGTH
);
}
void
update
(
const
void
*
data
,
const
size_t
len
)
{
hmac_
->
update
(
static_cast
<
const
Botan
::
byte
*>
(
data
),
len
);
}
void
sign
(
isc
::
dns
::
OutputBuffer
&
result
,
size_t
len
)
{
Botan
::
SecureVector
<
Botan
::
byte
>
b_result
(
hmac_
->
final
());
if
(
len
==
0
||
len
>
b_result
.
size
())
{
len
=
b_result
.
size
();
}
result
.
writeData
(
b_result
.
begin
(),
len
);
}
void
sign
(
void
*
result
,
size_t
len
)
{
Botan
::
SecureVector
<
Botan
::
byte
>
b_result
(
hmac_
->
final
());
size_t
output_size
=
getOutputLength
();
if
(
output_size
>
len
)
{
output_size
=
len
;
}
memcpy
(
result
,
b_result
.
begin
(),
output_size
);
}
std
::
vector
<
uint8_t
>
sign
(
size_t
len
)
{
Botan
::
SecureVector
<
Botan
::
byte
>
b_result
(
hmac_
->
final
());
if
(
len
==
0
||
len
>
b_result
.
size
())
{
return
(
std
::
vector
<
uint8_t
>
(
b_result
.
begin
(),
b_result
.
end
()));
}
else
{
return
(
std
::
vector
<
uint8_t
>
(
b_result
.
begin
(),
&
b_result
[
len
]));
}
Crypto
&
Crypto
::
getCrypto
()
{
Crypto
&
c
=
getCryptoInternal
();
if
(
!
c
.
impl_
)
{
c
.
initialize
();
}
bool
verify
(
const
void
*
sig
,
size_t
len
)
{
// Botan's verify_mac checks if len matches the output_length,
// which causes it to fail for truncated signatures, so we do
// the check ourselves
Botan
::
SecureVector
<
Botan
::
byte
>
our_mac
=
hmac_
->
final
();
if
(
len
==
0
||
len
>
getOutputLength
())
{
len
=
getOutputLength
();
}
return
(
Botan
::
same_mem
(
&
our_mac
[
0
],
static_cast
<
const
unsigned
char
*>
(
sig
),
len
));
}
private:
boost
::
scoped_ptr
<
Botan
::
HMAC
>
hmac_
;
};
HMAC
::
HMAC
(
const
void
*
secret
,
size_t
secret_length
,
const
HashAlgorithm
hash_algorithm
)
{
impl_
=
new
HMACImpl
(
secret
,
secret_length
,
hash_algorithm
);
}
HMAC
::~
HMAC
()
{
delete
impl_
;
}
size_t
HMAC
::
getOutputLength
()
const
{
return
(
impl_
->
getOutputLength
());
}
void
HMAC
::
update
(
const
void
*
data
,
const
size_t
len
)
{
impl_
->
update
(
data
,
len
);
return
c
;
}
void
HMAC
::
sign
(
isc
::
dns
::
OutputBuffer
&
result
,
size_t
len
)
{
impl_
->
sign
(
result
,
len
);
Crypto
&
Crypto
::
getCryptoInternal
()
{
static
Crypto
instance
;
return
(
instance
);
}
void
HMAC
::
sign
(
void
*
result
,
size_t
len
)
{
impl_
->
sign
(
result
,
len
);
}
std
::
vector
<
uint8_t
>
HMAC
::
sign
(
size_t
len
)
{
return
impl_
->
sign
(
len
);
Crypto
::
initialize
(
)
{
Crypto
&
c
=
getCryptoInternal
(
);
try
{
c
.
impl_
=
new
CryptoImpl
();
}
catch
(
const
Botan
::
Exception
&
ex
)
{
isc_throw
(
InitializationError
,
ex
.
what
());
}
}
bool
HMAC
::
verify
(
const
void
*
sig
,
const
size_t
len
)
{
return
(
impl_
->
verify
(
sig
,
len
));
HMAC
*
Crypto
::
createHMAC
(
const
void
*
secret
,
size_t
secret_len
,
const
HMAC
::
HashAlgorithm
hash_algorithm
)
{
return
new
HMAC
(
secret
,
secret_len
,
hash_algorithm
);
}
void
...
...
src/lib/crypto/crypto.h
View file @
e74f6d5e
...
...
@@ -18,6 +18,8 @@
#include
<boost/noncopyable.hpp>
#include
<crypto/crypto_hmac.h>
#ifndef _ISC_CRYPTO_H
#define _ISC_CRYPTO_H
...
...
@@ -67,110 +69,25 @@ class CryptoImpl;
/// Preferably, this object is created in the program's main() function
// Internal note: we can use this class later to initialize and manage
// dynamic (PKCS#11) libs
class
Crypto
{
class
Crypto
:
private
boost
::
noncopyable
{
public:
Crypto
();
~
Crypto
();
static
Crypto
&
getCrypto
();
static
void
initialize
();
bool
initialized
()
{
return
(
impl_
!=
NULL
);
}
HMAC
*
createHMAC
(
const
void
*
secret
,
size_t
secret_len
,
const
HMAC
::
HashAlgorithm
hash_algorithm
);
private:
static
Crypto
&
getCryptoInternal
();
Crypto
()
:
impl_
(
NULL
)
{};
~
Crypto
();
CryptoImpl
*
impl_
;
};
/// Forward declaration, pimpl style
class
HMACImpl
;
/// \brief HMAC support
///
/// This class is used to create and verify HMAC signatures
///
class
HMAC
:
private
boost
::
noncopyable
{
public:
enum
HashAlgorithm
{
MD5
=
0
,
///< MD5
SHA1
=
1
,
///< SHA-1
SHA256
=
2
,
///< SHA-256
UNKNOWN
=
3
///< This value can be used in conversion
/// functions, to be returned when the
/// input is unknown (but a value MUST be
/// returned), for instance when the input
/// is a Name or a string, and the return
/// value is a HashAlgorithm.
};
/// \brief Constructor from a secret and a hash algorithm
///
/// \exception UnsupportedAlgorithmException if the given algorithm
/// is unknown or not supported by the underlying library
/// \exception InvalidKeyLength if the given key secret_len is bad
///
/// Notes: if the secret is longer than the block size of its
/// algorithm, the constructor will run it through the hash
/// algorithm, and use the digest as the secret for this HMAC
/// operation
///
/// \param secret The secret to sign with
/// \param len The length of the secret
/// \param hash_algorithm The hash algorithm
explicit
HMAC
(
const
void
*
secret
,
size_t
secret_len
,
const
HashAlgorithm
hash_algorithm
);
/// \brief Destructor
~
HMAC
();
/// \brief Returns the output size of the digest
///
/// \return output size of the digest
size_t
getOutputLength
()
const
;
/// \brief Add data to digest
///
/// \param data The data to add
/// \param len The size of the data
void
update
(
const
void
*
data
,
const
size_t
len
);
/// \brief Calculate the final signature
///
/// The result will be appended to the given outputbuffer
///
/// \param result The OutputBuffer to append the result to
/// \param len The number of bytes from the result to copy. If this
/// value is smaller than the algorithms output size, the
/// result will be truncated. If this value is larger, or 0
/// (the default), it will be ignored
void
sign
(
isc
::
dns
::
OutputBuffer
&
result
,
size_t
len
=
0
);
/// \brief Calculate the final signature
///
/// len bytes of data from the result will be copied to *result
/// If len is larger than the output size, only output_size bytes
/// will be copied. If it is smaller, the output will be truncated
///
/// At least len bytes of data must be available for writing at
/// result
void
sign
(
void
*
result
,
size_t
len
);
/// \brief Calculate the final signatre
///
/// The result will be returned as a std::vector<uint8_t>
///
/// \param len The number of bytes from the result to copy. If this
/// value is smaller than the algorithms output size, the
/// result will be truncated. If this value is larger, or 0
/// (the default), it will be ignored
/// \return a vector containing the signature
std
::
vector
<
uint8_t
>
sign
(
size_t
len
=
0
);
/// \brief Verify an existing signature
///
/// \param sig The signature to verify
/// \param len The length of the signature. If this is non-zero,
/// and smaller than the output length of the algorithm,
/// only len bytes will be checked
/// \return true if the signature is correct, false otherwise
bool
verify
(
const
void
*
sig
,
size_t
len
);
private:
HMACImpl
*
impl_
;
};
/// Entry point for the API
/// If the library has not been initialized, this will automatically
/// initialize it with default values
/// \brief Create an HMAC signature for the given data
///
...
...
src/lib/crypto/crypto_hmac.cc
0 → 100644
View file @
e74f6d5e
#include
<crypto.h>
#include
<crypto/crypto_hmac.h>
#include
<boost/scoped_ptr.hpp>
#include
<botan/botan.h>
#include
<botan/hmac.h>
#include
<botan/hash.h>
#include
<botan/types.h>
namespace
{
const
char
*
getBotanHashAlgorithmName
(
isc
::
crypto
::
HMAC
::
HashAlgorithm
algorithm
)
{
switch
(
algorithm
)
{
case
isc
::
crypto
::
HMAC
::
MD5
:
return
(
"MD5"
);
break
;
case
isc
::
crypto
::
HMAC
::
SHA1
:
return
(
"SHA-1"
);
break
;
case
isc
::
crypto
::
HMAC
::
SHA256
:
return
(
"SHA-256"
);
break
;
case
isc
::
crypto
::
HMAC
::
UNKNOWN
:
return
(
"Unknown"
);
break
;
}
// compiler should have prevented us to reach this, since we have
// no default. But we need a return value anyway
return
(
"Unknown"
);
}
}
// local namespace
namespace
isc
{
namespace
crypto
{
class
HMACImpl
{
public:
explicit
HMACImpl
(
const
void
*
secret
,
size_t
secret_len
,
const
HMAC
::
HashAlgorithm
hash_algorithm
)
{
Botan
::
HashFunction
*
hash
;
try
{
hash
=
Botan
::
get_hash
(
getBotanHashAlgorithmName
(
hash_algorithm
));
}
catch
(
const
Botan
::
Algorithm_Not_Found
&
)
{
isc_throw
(
isc
::
crypto
::
UnsupportedAlgorithm
,
"Unknown hash algorithm: "
+
hash_algorithm
);
}
hmac_
.
reset
(
new
Botan
::
HMAC
::
HMAC
(
hash
));
// If the key length is larger than the block size, we hash the
// key itself first.
try
{
if
(
secret_len
>
hash
->
HASH_BLOCK_SIZE
)
{
Botan
::
SecureVector
<
Botan
::
byte
>
hashed_key
=
hash
->
process
(
static_cast
<
const
Botan
::
byte
*>
(
secret
),
secret_len
);
hmac_
->
set_key
(
hashed_key
.
begin
(),
hashed_key
.
size
());
}
else
{
hmac_
->
set_key
(
static_cast
<
const
Botan
::
byte
*>
(
secret
),
secret_len
);
}
}
catch
(
const
Botan
::
Invalid_Key_Length
&
ikl
)
{
isc_throw
(
BadKey
,
ikl
.
what
());
}
}
~
HMACImpl
()
{
}
size_t
getOutputLength
()
const
{
return
(
hmac_
->
OUTPUT_LENGTH
);
}
void
update
(
const
void
*
data
,
const
size_t
len
)
{
hmac_
->
update
(
static_cast
<
const
Botan
::
byte
*>
(
data
),
len
);
}
void
sign
(
isc
::
dns
::
OutputBuffer
&
result
,
size_t
len
)
{
Botan
::
SecureVector
<
Botan
::
byte
>
b_result
(
hmac_
->
final
());
if
(
len
==
0
||
len
>
b_result
.
size
())
{
len
=
b_result
.
size
();
}
result
.
writeData
(
b_result
.
begin
(),
len
);
}
void
sign
(
void
*
result
,
size_t
len
)
{
Botan
::
SecureVector
<
Botan
::
byte
>
b_result
(
hmac_
->
final
());
size_t
output_size
=
getOutputLength
();
if
(
output_size
>
len
)
{
output_size
=
len
;
}
memcpy
(
result
,
b_result
.
begin
(),
output_size
);
}
std
::
vector
<
uint8_t
>
sign
(
size_t
len
)
{
Botan
::
SecureVector
<
Botan
::
byte
>
b_result
(
hmac_
->
final
());
if
(
len
==
0
||
len
>
b_result
.
size
())
{
return
(
std
::
vector
<
uint8_t
>
(
b_result
.
begin
(),
b_result
.
end
()));
}
else
{
return
(
std
::
vector
<
uint8_t
>
(
b_result
.
begin
(),
&
b_result
[
len
]));
}
}
bool
verify
(
const
void
*
sig
,
size_t
len
)
{
// Botan's verify_mac checks if len matches the output_length,
// which causes it to fail for truncated signatures, so we do
// the check ourselves
Botan
::
SecureVector
<
Botan
::
byte
>
our_mac
=
hmac_
->
final
();
if
(
len
==
0
||
len
>
getOutputLength
())
{
len
=
getOutputLength
();
}
return
(
Botan
::
same_mem
(
&
our_mac
[
0
],
static_cast
<
const
unsigned
char
*>
(
sig
),
len
));
}
private:
boost
::
scoped_ptr
<
Botan
::
HMAC
>
hmac_
;
};
HMAC
::
HMAC
(
const
void
*
secret
,
size_t
secret_length
,
const
HashAlgorithm
hash_algorithm
)
{
impl_
=
new
HMACImpl
(
secret
,
secret_length
,
hash_algorithm
);
}
HMAC
::~
HMAC
()
{
delete
impl_
;
}
size_t
HMAC
::
getOutputLength
()
const
{
return
(
impl_
->
getOutputLength
());
}
void
HMAC
::
update
(
const
void
*
data
,
const
size_t
len
)
{
impl_
->
update
(
data
,
len
);
}
void
HMAC
::
sign
(
isc
::
dns
::
OutputBuffer
&
result
,
size_t
len
)
{
impl_
->
sign
(
result
,
len
);
}
void
HMAC
::
sign
(
void
*
result
,
size_t
len
)
{
impl_
->
sign
(
result
,
len
);
}
std
::
vector
<
uint8_t
>
HMAC
::
sign
(
size_t
len
)
{
return
impl_
->
sign
(
len
);
}
bool
HMAC
::
verify
(
const
void
*
sig
,
const
size_t
len
)
{
return
(
impl_
->
verify
(
sig
,
len
));
}
}
// namespace crypto
}
// namespace isc
src/lib/crypto/crypto_hmac.h
0 → 100644
View file @
e74f6d5e
// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include
<string>
#include
<dns/buffer.h>
#include
<exceptions/exceptions.h>
#include
<boost/noncopyable.hpp>
#ifndef _ISC_CRYPTO_HMAC_H
#define _ISC_CRYPTO_HMAC_H
namespace
isc
{
namespace
crypto
{
/// Forward declaration, pimpl style
class
HMACImpl
;
/// \brief HMAC support
///
/// This class is used to create and verify HMAC signatures
///
class
HMAC
:
private
boost
::
noncopyable
{
public:
enum
HashAlgorithm
{
MD5
=
0
,
///< MD5
SHA1
=
1
,
///< SHA-1
SHA256
=
2
,
///< SHA-256
UNKNOWN
=
3
///< This value can be used in conversion
/// functions, to be returned when the
/// input is unknown (but a value MUST be
/// returned), for instance when the input
/// is a Name or a string, and the return
/// value is a HashAlgorithm.
};
/// \brief Constructor from a secret and a hash algorithm
///
/// \exception UnsupportedAlgorithmException if the given algorithm
/// is unknown or not supported by the underlying library
/// \exception InvalidKeyLength if the given key secret_len is bad
///
/// Notes: if the secret is longer than the block size of its
/// algorithm, the constructor will run it through the hash
/// algorithm, and use the digest as the secret for this HMAC
/// operation
///
/// \param secret The secret to sign with
/// \param len The length of the secret
/// \param hash_algorithm The hash algorithm
explicit
HMAC
(
const
void
*
secret
,
size_t
secret_len
,
const
HashAlgorithm
hash_algorithm
);
/// \brief Destructor
~
HMAC
();
/// \brief Returns the output size of the digest
///
/// \return output size of the digest
size_t
getOutputLength
()
const
;
/// \brief Add data to digest
///
/// \param data The data to add
/// \param len The size of the data
void
update
(
const
void
*
data
,
const
size_t
len
);
/// \brief Calculate the final signature
///
/// The result will be appended to the given outputbuffer
///
/// \param result The OutputBuffer to append the result to
/// \param len The number of bytes from the result to copy. If this
/// value is smaller than the algorithms output size, the
/// result will be truncated. If this value is larger, or 0
/// (the default), it will be ignored
void
sign
(
isc
::
dns
::
OutputBuffer
&
result
,
size_t
len
=
0
);
/// \brief Calculate the final signature
///
/// len bytes of data from the result will be copied to *result
/// If len is larger than the output size, only output_size bytes
/// will be copied. If it is smaller, the output will be truncated
///
/// At least len bytes of data must be available for writing at
/// result
void
sign
(
void
*
result
,
size_t
len
);
/// \brief Calculate the final signatre
///
/// The result will be returned as a std::vector<uint8_t>
///
/// \param len The number of bytes from the result to copy. If this
/// value is smaller than the algorithms output size, the
/// result will be truncated. If this value is larger, or 0
/// (the default), it will be ignored
/// \return a vector containing the signature
std
::
vector
<
uint8_t
>
sign
(
size_t
len
=
0
);