static DWORD VerifyWeakSignature( TMPQArchive * ha, PMPQ_SIGNATURE_INFO pSI) { BYTE RevSignature[MPQ_WEAK_SIGNATURE_SIZE]; BYTE Md5Digest[MD5_DIGEST_SIZE]; rsa_key key; int hash_idx = find_hash("md5"); int result = 0; // Calculate hash of the entire archive, skipping the (signature) file if(!CalculateMpqHashMd5(ha, pSI, Md5Digest)) return ERROR_VERIFY_FAILED; // Import the Blizzard key in OpenSSL format if(!decode_base64_key(szBlizzardWeakPublicKey, &key)) return ERROR_VERIFY_FAILED; // Verify the signature memcpy(RevSignature, &pSI->Signature[8], MPQ_WEAK_SIGNATURE_SIZE); memrev(RevSignature, MPQ_WEAK_SIGNATURE_SIZE); rsa_verify_hash_ex(RevSignature, MPQ_WEAK_SIGNATURE_SIZE, Md5Digest, sizeof(Md5Digest), LTC_LTC_PKCS_1_V1_5, hash_idx, 0, &result, &key); rsa_free(&key); // Return the result return result ? ERROR_WEAK_SIGNATURE_OK : ERROR_WEAK_SIGNATURE_ERROR; }
int SSignFileFinish(TMPQArchive * ha) { MPQ_SIGNATURE_INFO si; unsigned long signature_len = MPQ_WEAK_SIGNATURE_SIZE; BYTE WeakSignature[MPQ_SIGNATURE_FILE_SIZE]; BYTE Md5Digest[MD5_DIGEST_SIZE]; rsa_key key; int hash_idx = find_hash("md5"); // Sanity checks assert((ha->dwFlags & MPQ_FLAG_CHANGED) == 0); assert(ha->dwFileFlags3 == MPQ_FILE_EXISTS); // Query the weak signature info memset(&si, 0, sizeof(MPQ_SIGNATURE_INFO)); if(!QueryMpqSignatureInfo(ha, &si)) return ERROR_FILE_CORRUPT; // There must be exactly one signature if(si.SignatureTypes != SIGNATURE_TYPE_WEAK) return ERROR_FILE_CORRUPT; // Calculate MD5 of the entire archive if(!CalculateMpqHashMd5(ha, &si, Md5Digest)) return ERROR_VERIFY_FAILED; // Decode the private key if(!decode_base64_key(szBlizzardWeakPrivateKey, &key)) return ERROR_VERIFY_FAILED; // Sign the hash memset(WeakSignature, 0, sizeof(WeakSignature)); rsa_sign_hash_ex(Md5Digest, sizeof(Md5Digest), WeakSignature + 8, &signature_len, LTC_LTC_PKCS_1_V1_5, 0, 0, hash_idx, 0, &key); memrev(WeakSignature + 8, MPQ_WEAK_SIGNATURE_SIZE); rsa_free(&key); // Write the signature to the MPQ. Don't use SFile* functions, but write the hash directly if(!FileStream_Write(ha->pStream, &si.BeginExclude, WeakSignature, MPQ_SIGNATURE_FILE_SIZE)) return GetLastError(); return ERROR_SUCCESS; }
static DWORD VerifyStrongSignatureWithKey( unsigned char * reversed_signature, unsigned char * padded_digest, const char * szPublicKey) { rsa_key key; int result = 0; // Import the Blizzard key in OpenSSL format if (!decode_base64_key(szPublicKey, &key)) { assert(false); return ERROR_VERIFY_FAILED; } // Verify the signature #warning rsa_verify_simple is missing // if (rsa_verify_simple(reversed_signature, MPQ_STRONG_SIGNATURE_SIZE, padded_digest, MPQ_STRONG_SIGNATURE_SIZE, &result, &key) != CRYPT_OK) // return ERROR_VERIFY_FAILED; // Free the key and return result rsa_free(&key); return result ? ERROR_STRONG_SIGNATURE_OK : ERROR_STRONG_SIGNATURE_ERROR; }
/* * Parse the dnskey from the string. The string contains the flags, * protocol, algorithm and the base64 key delimited by spaces. */ int val_parse_dnskey_string(char *keystr, size_t keystrlen, val_dnskey_rdata_t ** dnskey_rdata) { char *sp = keystr; char *ep = sp + keystrlen; char token[NS_MAXDNAME]; char *keyptr = NULL; char *cp; size_t bufsize; size_t buflen; u_char *buf; u_char *bp; u_int16_t flags; if (keystr == NULL || dnskey_rdata == NULL) return VAL_BAD_ARGUMENT; (*dnskey_rdata) = (val_dnskey_rdata_t *) MALLOC(sizeof(val_dnskey_rdata_t)); if ((*dnskey_rdata) == NULL) return VAL_OUT_OF_MEMORY; TOK_IN_STR(); (*dnskey_rdata)->flags = (int)strtol(token, (char **)NULL, 10); TOK_IN_STR(); (*dnskey_rdata)->protocol = (int)strtol(token, (char **)NULL, 10); TOK_IN_STR(); (*dnskey_rdata)->algorithm = (int)strtol(token, (char **)NULL, 10); if (sp >= ep) { FREE(*dnskey_rdata); *dnskey_rdata = NULL; return VAL_CONF_PARSE_ERROR; } /* * What follows is the public key in base64. */ /* * Remove any white spaces */ for (cp = sp; sp < ep; sp++) { if (!isspace(*sp)) { if (keyptr == NULL) keyptr = cp; if (cp != sp) *cp = *sp; cp++; } } *cp = '\0'; ep = cp; /* this is the last character in the public key */ if (keyptr == NULL || keyptr >= ep) { FREE(*dnskey_rdata); *dnskey_rdata = NULL; return VAL_CONF_PARSE_ERROR; } bufsize = ep - keyptr; (*dnskey_rdata)->public_key = (u_char *) MALLOC(bufsize * sizeof(char)); if ((*dnskey_rdata)->public_key == NULL) { FREE(*dnskey_rdata); *dnskey_rdata = NULL; return VAL_OUT_OF_MEMORY; } /* * decode the base64 public key */ if (((*dnskey_rdata)->public_key_len = decode_base64_key(keyptr, (*dnskey_rdata)-> public_key, bufsize)) <= 0) { FREE((*dnskey_rdata)->public_key); FREE(*dnskey_rdata); *dnskey_rdata = NULL; return VAL_BAD_ARGUMENT; } /* * For calculating the keytag, we need the * complete DNSKEY RDATA in wire format */ buflen = (*dnskey_rdata)->public_key_len + sizeof(u_int16_t) + /* flags */ sizeof(u_char) + /* proto */ sizeof(u_char); /*algo */ buf = (u_char *) MALLOC(buflen * sizeof(u_char)); if (buf == NULL) { FREE((*dnskey_rdata)->public_key); FREE(*dnskey_rdata); *dnskey_rdata = NULL; return VAL_OUT_OF_MEMORY; } bp = buf; flags = (*dnskey_rdata)->flags; memcpy(bp, &flags, sizeof(u_int16_t)); bp += sizeof(u_int16_t); *bp = (*dnskey_rdata)->protocol; bp++; *bp = (*dnskey_rdata)->algorithm; bp++; memcpy(bp, (*dnskey_rdata)->public_key, (*dnskey_rdata)->public_key_len); /* * Calculate the keytag */ if ((*dnskey_rdata)->algorithm == ALG_RSAMD5) { (*dnskey_rdata)->key_tag = rsamd5_keytag(buf, buflen); } else { (*dnskey_rdata)->key_tag = keytag(buf, buflen); } (*dnskey_rdata)->next = NULL; FREE(buf); return VAL_NO_ERROR; }