Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions src/libmoex/base/digest/Sha.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
//
// Created by everettjf
// Copyright © 2017 everettjf. All rights reserved.
//
// Small dependency-free SHA-1 / SHA-256 used to compute code-signing cdhash.
// libmoex must not depend on Qt, so we cannot use QCryptographicHash here.
#ifndef MOEX_DIGEST_SHA_H
#define MOEX_DIGEST_SHA_H

#include <cstdint>
#include <cstddef>
#include <string>
#include <vector>

namespace moex { namespace digest {

inline std::vector<uint8_t> Sha1(const uint8_t *data, std::size_t len) {
uint32_t h0 = 0x67452301, h1 = 0xEFCDAB89, h2 = 0x98BADCFE, h3 = 0x10325476, h4 = 0xC3D2E1F0;
const uint64_t bitlen = static_cast<uint64_t>(len) * 8;
std::vector<uint8_t> msg(data, data + len);
msg.push_back(0x80);
while (msg.size() % 64 != 56) msg.push_back(0x00);
for (int i = 7; i >= 0; --i) msg.push_back(static_cast<uint8_t>(bitlen >> (i * 8)));

auto rol = [](uint32_t x, uint32_t n) { return (x << n) | (x >> (32 - n)); };
for (std::size_t off = 0; off < msg.size(); off += 64) {
uint32_t w[80];
for (int i = 0; i < 16; ++i)
w[i] = (static_cast<uint32_t>(msg[off + i * 4]) << 24) |
(static_cast<uint32_t>(msg[off + i * 4 + 1]) << 16) |
(static_cast<uint32_t>(msg[off + i * 4 + 2]) << 8) |
static_cast<uint32_t>(msg[off + i * 4 + 3]);
for (int i = 16; i < 80; ++i) w[i] = rol(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);

uint32_t a = h0, b = h1, c = h2, d = h3, e = h4;
for (int i = 0; i < 80; ++i) {
uint32_t f, k;
if (i < 20) { f = (b & c) | ((~b) & d); k = 0x5A827999; }
else if (i < 40) { f = b ^ c ^ d; k = 0x6ED9EBA1; }
else if (i < 60) { f = (b & c) | (b & d) | (c & d); k = 0x8F1BBCDC; }
else { f = b ^ c ^ d; k = 0xCA62C1D6; }
const uint32_t tmp = rol(a, 5) + f + e + k + w[i];
e = d; d = c; c = rol(b, 30); b = a; a = tmp;
}
h0 += a; h1 += b; h2 += c; h3 += d; h4 += e;
}

const uint32_t hs[5] = {h0, h1, h2, h3, h4};
std::vector<uint8_t> out(20);
for (int i = 0; i < 5; ++i) {
out[i * 4] = static_cast<uint8_t>(hs[i] >> 24);
out[i * 4 + 1] = static_cast<uint8_t>(hs[i] >> 16);
out[i * 4 + 2] = static_cast<uint8_t>(hs[i] >> 8);
out[i * 4 + 3] = static_cast<uint8_t>(hs[i]);
}
return out;
}

inline std::vector<uint8_t> Sha256(const uint8_t *data, std::size_t len) {
static const 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};
uint32_t h[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};

const uint64_t bitlen = static_cast<uint64_t>(len) * 8;
std::vector<uint8_t> msg(data, data + len);
msg.push_back(0x80);
while (msg.size() % 64 != 56) msg.push_back(0x00);
for (int i = 7; i >= 0; --i) msg.push_back(static_cast<uint8_t>(bitlen >> (i * 8)));

auto rotr = [](uint32_t x, uint32_t n) { return (x >> n) | (x << (32 - n)); };
for (std::size_t off = 0; off < msg.size(); off += 64) {
uint32_t w[64];
for (int i = 0; i < 16; ++i)
w[i] = (static_cast<uint32_t>(msg[off + i * 4]) << 24) |
(static_cast<uint32_t>(msg[off + i * 4 + 1]) << 16) |
(static_cast<uint32_t>(msg[off + i * 4 + 2]) << 8) |
static_cast<uint32_t>(msg[off + i * 4 + 3]);
for (int i = 16; i < 64; ++i) {
const uint32_t s0 = rotr(w[i - 15], 7) ^ rotr(w[i - 15], 18) ^ (w[i - 15] >> 3);
const uint32_t s1 = rotr(w[i - 2], 17) ^ rotr(w[i - 2], 19) ^ (w[i - 2] >> 10);
w[i] = w[i - 16] + s0 + w[i - 7] + s1;
}

uint32_t a = h[0], b = h[1], c = h[2], d = h[3], e = h[4], f = h[5], g = h[6], hh = h[7];
for (int i = 0; i < 64; ++i) {
const uint32_t S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
const uint32_t ch = (e & f) ^ ((~e) & g);
const uint32_t t1 = hh + S1 + ch + K[i] + w[i];
const uint32_t S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
const uint32_t maj = (a & b) ^ (a & c) ^ (b & c);
const uint32_t t2 = S0 + maj;
hh = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;
}
h[0] += a; h[1] += b; h[2] += c; h[3] += d; h[4] += e; h[5] += f; h[6] += g; h[7] += hh;
}

std::vector<uint8_t> out(32);
for (int i = 0; i < 8; ++i) {
out[i * 4] = static_cast<uint8_t>(h[i] >> 24);
out[i * 4 + 1] = static_cast<uint8_t>(h[i] >> 16);
out[i * 4 + 2] = static_cast<uint8_t>(h[i] >> 8);
out[i * 4 + 3] = static_cast<uint8_t>(h[i]);
}
return out;
}

inline std::string ToHex(const std::vector<uint8_t> &d) {
static const char *hx = "0123456789abcdef";
std::string s;
s.reserve(d.size() * 2);
for (uint8_t b : d) {
s += hx[b >> 4];
s += hx[b & 0x0f];
}
return s;
}

}} // namespace moex::digest

#endif // MOEX_DIGEST_SHA_H
18 changes: 18 additions & 0 deletions src/libmoex/viewnode/views/CodeSignatureViewNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//

#include "CodeSignatureViewNode.h"
#include "libmoex/base/digest/Sha.h"
#include <cstring>

MOEX_NAMESPACE_BEGIN
Expand Down Expand Up @@ -205,6 +206,23 @@ void CodeSignatureViewNode::InitViewDatas() {
t->AddRow({AsAddress(base_off + cd_off), "Code Directory",
fmt::format("version=0x{}", AsShortHexString(cd_version))});

// cdhash: the digest of the whole Code Directory blob (per its hash
// type), truncated to the canonical 20 bytes.
const uint32_t cd_len = ReadBE32(cd + 4);
if (cd_len >= 8 && static_cast<uint64_t>(cd_off) + cd_len <= datasize) {
std::vector<uint8_t> digest;
if (hash_type == 1) {
digest = moex::digest::Sha1(cd, cd_len);
} else if (hash_type == 2 || hash_type == 3) {
digest = moex::digest::Sha256(cd, cd_len);
}
if (!digest.empty()) {
if (digest.size() > 20) digest.resize(20);
t->AddRow({AsAddress(base_off + cd_off), "CD Hash (cdhash)",
moex::digest::ToHex(digest)});
}
}

const std::string identifier =
ReadBlobCString(cd, datasize - cd_off, ident_off);
if (!identifier.empty()) {
Expand Down
Loading