forked from audacity/audacity
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
325 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# SPDX-License-Identifier: GPL-2.0-or-later | ||
# SPDX-FileName: CMakeLists.txt | ||
# SPDX-FileContributor: Dmitry Vedenko | ||
#[[ | ||
A set of helpers for working with cryptographic functions. | ||
]] | ||
|
||
set( SOURCES | ||
crypto/SHA256.cpp | ||
crypto/SHA256.h | ||
) | ||
set( LIBRARIES | ||
PUBLIC | ||
) | ||
audacity_library( lib-crypto "${SOURCES}" "${LIBRARIES}" | ||
"" "" ) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
/* | ||
* SPDX-License-Identifier: GPL-2.0-or-later | ||
* SPDX-FileName: SHA256.h | ||
* SPDX-FileContributor: Dmitry Vedenko | ||
* | ||
* Based on a public domain code by Brad Conte. | ||
*/ | ||
|
||
#include "SHA256.h" | ||
|
||
#include <cassert> | ||
#include <cstring> | ||
|
||
namespace crypto | ||
{ | ||
|
||
namespace | ||
{ | ||
constexpr uint32_t K[64] = { | ||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, | ||
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, | ||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, | ||
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, | ||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, | ||
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, | ||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, | ||
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, | ||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, | ||
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, | ||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 | ||
}; | ||
|
||
#define ROTLEFT(a, b) (((a) << (b)) | ((a) >> (32 - (b)))) | ||
#define ROTRIGHT(a, b) (((a) >> (b)) | ((a) << (32 - (b)))) | ||
|
||
#define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z))) | ||
#define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) | ||
#define EP0(x) (ROTRIGHT(x, 2) ^ ROTRIGHT(x, 13) ^ ROTRIGHT(x, 22)) | ||
#define EP1(x) (ROTRIGHT(x, 6) ^ ROTRIGHT(x, 11) ^ ROTRIGHT(x, 25)) | ||
#define SIG0(x) (ROTRIGHT(x, 7) ^ ROTRIGHT(x, 18) ^ ((x) >> 3)) | ||
#define SIG1(x) (ROTRIGHT(x, 17) ^ ROTRIGHT(x, 19) ^ ((x) >> 10)) | ||
|
||
void sha256_transform(uint32_t state[8], const uint8_t data[64]) | ||
{ | ||
uint32_t m[SHA256::BLOCK_SIZE]; | ||
|
||
int i = 0; | ||
int j = 0; | ||
|
||
for (; i < 16; ++i, j += 4) | ||
m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | | ||
(data[j + 3]); | ||
|
||
for (; i < 64; ++i) | ||
m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; | ||
|
||
uint32_t a = state[0]; | ||
uint32_t b = state[1]; | ||
uint32_t c = state[2]; | ||
uint32_t d = state[3]; | ||
uint32_t e = state[4]; | ||
uint32_t f = state[5]; | ||
uint32_t g = state[6]; | ||
uint32_t h = state[7]; | ||
|
||
for (i = 0; i < SHA256::BLOCK_SIZE; ++i) | ||
{ | ||
const uint32_t t1 = h + EP1(e) + CH(e, f, g) + K[i] + m[i]; | ||
const uint32_t t2 = EP0(a) + MAJ(a, b, c); | ||
|
||
h = g; | ||
g = f; | ||
f = e; | ||
e = d + t1; | ||
d = c; | ||
c = b; | ||
b = a; | ||
a = t1 + t2; | ||
} | ||
|
||
state[0] += a; | ||
state[1] += b; | ||
state[2] += c; | ||
state[3] += d; | ||
state[4] += e; | ||
state[5] += f; | ||
state[6] += g; | ||
state[7] += h; | ||
} | ||
|
||
} // namespace | ||
|
||
SHA256::SHA256() | ||
{ | ||
Reset(); | ||
} | ||
|
||
void SHA256::Update(const void* data, std::size_t size) | ||
{ | ||
const uint8_t* dataPtr = static_cast<const uint8_t*>(data); | ||
|
||
while (size > 0) | ||
{ | ||
std::size_t blockSize = | ||
std::min<size_t>(size, SHA256::BLOCK_SIZE - mBufferLength); | ||
|
||
std::memcpy(mBuffer + mBufferLength, dataPtr, blockSize); | ||
|
||
mBufferLength += blockSize; | ||
dataPtr += blockSize; | ||
size -= blockSize; | ||
|
||
if (mBufferLength == SHA256::BLOCK_SIZE) | ||
{ | ||
sha256_transform(mState, mBuffer); | ||
mBitLength += 512; | ||
mBufferLength = 0; | ||
} | ||
} | ||
} | ||
|
||
void SHA256::Update(const char* zString) | ||
{ | ||
Update(zString, std::strlen(zString)); | ||
} | ||
|
||
std::string SHA256::Finalize() | ||
{ | ||
uint8_t pad[SHA256::BLOCK_SIZE]; | ||
std::size_t padLength; | ||
|
||
// `mBufferLength` is always less than SHA256::BLOCK_SIZE. See `Update` | ||
// method. | ||
assert(mBufferLength < SHA256::BLOCK_SIZE); | ||
|
||
mBitLength += mBufferLength * 8; | ||
|
||
if (mBufferLength < 56) | ||
{ | ||
mBuffer[mBufferLength++] = 0x80; | ||
std::memset(mBuffer + mBufferLength, 0, 56 - mBufferLength); | ||
} | ||
else | ||
{ | ||
mBuffer[mBufferLength++] = 0x80; | ||
std::memset( | ||
mBuffer + mBufferLength, 0, SHA256::BLOCK_SIZE - mBufferLength); | ||
sha256_transform(mState, mBuffer); | ||
std::memset(mBuffer, 0, 56); | ||
} | ||
|
||
|
||
mBuffer[56] = (mBitLength >> 56) & 0xff; | ||
mBuffer[57] = (mBitLength >> 48) & 0xff; | ||
mBuffer[58] = (mBitLength >> 40) & 0xff; | ||
mBuffer[59] = (mBitLength >> 32) & 0xff; | ||
mBuffer[60] = (mBitLength >> 24) & 0xff; | ||
mBuffer[61] = (mBitLength >> 16) & 0xff; | ||
mBuffer[62] = (mBitLength >> 8) & 0xff; | ||
mBuffer[63] = (mBitLength >> 0) & 0xff; | ||
|
||
sha256_transform(mState, mBuffer); | ||
|
||
uint8_t result[SHA256::HASH_SIZE]; | ||
|
||
for (int i = 0; i < 8; ++i) | ||
{ | ||
result[i * 4 + 0] = (mState[i] >> 24) & 0xff; | ||
result[i * 4 + 1] = (mState[i] >> 16) & 0xff; | ||
result[i * 4 + 2] = (mState[i] >> 8) & 0xff; | ||
result[i * 4 + 3] = (mState[i] >> 0) & 0xff; | ||
} | ||
|
||
Reset(); | ||
|
||
// Convert to hex string | ||
constexpr char hexChars[] = "0123456789ABCDEF"; | ||
std::string resultStr; | ||
resultStr.resize(HASH_SIZE * 2); | ||
|
||
for (int i = 0; i < SHA256::HASH_SIZE; ++i) | ||
{ | ||
resultStr[i * 2 + 0] = hexChars[(result[i] >> 4) & 0xf]; | ||
resultStr[i * 2 + 1] = hexChars[result[i] & 0xf]; | ||
} | ||
|
||
return resultStr; | ||
} | ||
|
||
void SHA256::Reset() | ||
{ | ||
mBitLength = 0; | ||
|
||
mState[0] = 0x6a09e667; | ||
mState[1] = 0xbb67ae85; | ||
mState[2] = 0x3c6ef372; | ||
mState[3] = 0xa54ff53a; | ||
mState[4] = 0x510e527f; | ||
mState[5] = 0x9b05688c; | ||
mState[6] = 0x1f83d9ab; | ||
mState[7] = 0x5be0cd19; | ||
|
||
std::memset(mBuffer, 0, sizeof(mBuffer)); | ||
mBufferLength = 0; | ||
} | ||
|
||
} // namespace crypto |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/* | ||
* SPDX-License-Identifier: GPL-2.0-or-later | ||
* SPDX-FileName: SHA256.h | ||
* SPDX-FileContributor: Dmitry Vedenko | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <cstdint> | ||
#include <cstddef> | ||
|
||
#include <string> | ||
|
||
namespace crypto | ||
{ | ||
class CRYPTO_API SHA256 final | ||
{ | ||
public: | ||
static constexpr std::size_t HASH_SIZE = 32; | ||
static constexpr std::size_t BLOCK_SIZE = 64; | ||
|
||
SHA256(); | ||
|
||
SHA256(const SHA256&) = delete; | ||
SHA256(SHA256&&) = delete; | ||
SHA256& operator=(const SHA256&) = delete; | ||
SHA256& operator=(SHA256&&) = delete; | ||
|
||
void Update(const void* data, std::size_t size); | ||
void Update(const char* zString); | ||
|
||
template<typename T> | ||
void Update(const T& data) | ||
{ | ||
Update(data.data(), data.size()); | ||
} | ||
|
||
std::string Finalize(); | ||
|
||
void Reset(); | ||
|
||
private: | ||
uint64_t mBitLength; | ||
uint32_t mState[8]; | ||
uint8_t mBuffer[BLOCK_SIZE]; | ||
uint32_t mBufferLength; | ||
}; // class SHA256 | ||
|
||
template<typename T> | ||
std::string sha256(const T& data) | ||
{ | ||
SHA256 hasher; | ||
hasher.Update(data); | ||
return hasher.Finalize(); | ||
} | ||
} // namespace crypto |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
add_unit_test( | ||
NAME | ||
lib-crypto | ||
SOURCES | ||
CryptoTests.cpp | ||
LIBRARIES | ||
lib-crypto-interface | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* | ||
* SPDX-License-Identifier: GPL-2.0-or-later | ||
* SPDX-FileName: CryptoTests.cpp | ||
* SPDX-FileContributor: Dmitry Vedenko | ||
*/ | ||
|
||
#include <catch2/catch.hpp> | ||
|
||
#include "crypto/SHA256.h" | ||
|
||
TEST_CASE("SHA256", "") | ||
{ | ||
crypto::SHA256 sha256; | ||
|
||
REQUIRE(sha256.Finalize() == "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855"); | ||
|
||
sha256.Update("a"); | ||
|
||
REQUIRE( | ||
sha256.Finalize() == | ||
"CA978112CA1BBDCAFAC231B39A23DC4DA786EFF8147C4E72B9807785AFEE48BB"); | ||
|
||
sha256.Update("bc", 2); | ||
|
||
REQUIRE( | ||
sha256.Finalize() == | ||
"1E0BBD6C686BA050B8EB03FFEEDC64FDC9D80947FCE821ABBE5D6DC8D252C5AC"); | ||
|
||
REQUIRE( | ||
crypto::sha256("Audacity") == | ||
"CF21DBCF13FC6B66CCBF713B88AD02EC1EF0C6196ACAF28B0FB48D04858A5D04"); | ||
|
||
REQUIRE( | ||
crypto::sha256( | ||
" is a free, open source, cross-platform audio software for multi-track recording and editing.") == | ||
"00E7C81A5357B1734035CE4CAE5DC0B3F886D22C8AF2E3952E2F5569A994B8A8"); | ||
} |