#pragma once #include #include "bitstream.h" #include "base64.h" #include "base32.h" #ifdef _WIN32 #include #endif using namespace std; class KeyValidatorImpl { public: KeyValidatorImpl() { } KeyValidatorImpl(const LicenseTemplateImpl* templ, const char * key = NULL) { SetKeyTemplate(templ); if (key) SetKey(key); } ~KeyValidatorImpl() { } void SetKeyTemplate(const LicenseTemplateImpl* templ) { m_keyTemplate = templ; if (templ->m_validationDataSize) { m_validationData.Create(templ->m_validationDataSize); for (const auto& field : m_keyTemplate->m_validationFields) m_validationData.AddField(field.first.c_str(), field.second.type, field.second.size, field.second.offset); } else m_validationData.Create(0); } void SetValidationData(const char * fieldName, const void * buf, int len) { m_validationData.Set(fieldName, buf, len); } void SetValidationData(const char * fieldName, const char * data) { m_validationData.Set(fieldName, data); } void SetValidationData(const char * fieldName, int data) { m_validationData.Set(fieldName, data); } void SetValidationData(const char * fieldName, int year, int month, int day) { m_validationData.Set(fieldName, year, month, day); } void SetKey(const char * licKey) { if (!licKey) throw new LicensingException(STATUS_INVALID_PARAM, "invalid license key"); string key(licKey); if (key.length() < m_keyTemplate->GetCharactersPerGroup() * m_keyTemplate->GetNumberOfGroups() + strlen(m_keyTemplate->GetHeader()) + strlen(m_keyTemplate->GetFooter()) + strlen(m_keyTemplate->GetGroupSeparator()) * (m_keyTemplate->GetNumberOfGroups() - 1)) { throw new LicensingException(STATUS_INVALID_LICENSE_KEY, "invalid license key (too short)"); } // remove header and footer (if any) if (!m_keyTemplate->m_header.empty()) { key.erase(0, m_keyTemplate->m_header.length() + 2); } if (!m_keyTemplate->m_footer.empty()) { key.erase(key.length() - m_keyTemplate->m_footer.length() - 2, m_keyTemplate->m_footer.length() + 2); } // ungroup license key for (int i = 0, erasePos = 0; i < m_keyTemplate->m_numGroups - 1; i++) { erasePos += m_keyTemplate->m_charsPerGroup; key.erase(erasePos, m_keyTemplate->m_groupSeparator.length()); } // decode license key switch ( m_keyTemplate->m_keyEncoding ) { case ENCODING_BASE32X: { BASE32 base32; int padLen; int len = base32.encode_pad_length(((int)key.length() * 5 + 7) >> 3, &padLen); if (len > (int)key.length()) key.append(len - key.length(), 'A'); if (padLen) key.append(padLen,'='); auto keyBuf = base32.decode(key.c_str(), (int)key.length(), &len ); if (keyBuf.empty()) throw new LicensingException(STATUS_INVALID_LICENSE_KEY); // reverse last byte keyBuf[ len - 1 ] = (unsigned char)(((keyBuf[ len - 1 ] * 0x0802LU & 0x22110LU) | (keyBuf[ len - 1 ] * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16); m_keyData.Attach(keyBuf, m_keyTemplate->m_keyEncoding * m_keyTemplate->m_charsPerGroup * m_keyTemplate->m_numGroups); } break; case ENCODING_BASE64X: { BASE64 base64; int padLen; int len = base64.encode_pad_length(((int)key.length() * 6 + 7) >> 3, &padLen); if (len > (int)key.length()) key.append(len - key.length(), 'A'); if (padLen) key.append(padLen,'='); auto keyBuf = base64.decode(key.c_str(), (int)key.length(), &len ); if (keyBuf.empty()) throw new LicensingException(STATUS_INVALID_LICENSE_KEY); // reverse last byte keyBuf[ len - 1 ] = (unsigned char)(((keyBuf[ len - 1 ] * 0x0802LU & 0x22110LU) | (keyBuf[ len - 1 ] * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16); m_keyData.Attach(keyBuf, m_keyTemplate->m_keyEncoding * m_keyTemplate->m_charsPerGroup * m_keyTemplate->m_numGroups); } break; default: throw new LicensingException(STATUS_INVALID_KEY_ENCODING); } for (const auto& field : m_keyTemplate->m_dataFields) m_keyData.AddField(field.first.c_str(), field.second.type, field.second.size, field.second.offset); } bool IsKeyValid() { ECC::Verifier verifier; BitStream signedData, signature; signedData.Create(m_keyTemplate->m_dataSize + m_keyTemplate->m_validationDataSize); signedData.Clear(); if (m_keyTemplate->m_dataSize) signedData.Write(m_keyData.GetBuffer(), m_keyTemplate->m_dataSize); if (m_keyTemplate->m_validationDataSize) signedData.Write(m_validationData.GetBuffer(), m_keyTemplate->m_validationDataSize); signature.Create(m_keyTemplate->m_signatureSize); m_keyData.GetBitStream().Seek(m_keyTemplate->m_dataSize); m_keyData.GetBitStream().Read(signature.GetBuffer(), m_keyTemplate->m_signatureSize); signature.ReleaseBuffer(m_keyTemplate->m_signatureSize); signature.Seek(m_keyTemplate->m_signatureSize); signature.ZeroPadToNextByte(); signature.ReleaseBuffer(m_keyTemplate->m_signatureSize); // we use a different algorithm than ECDSA when the signature size must be smaller than twice the key size if (m_keyTemplate->m_signatureSize < (m_keyTemplate->m_signatureKeySize << 1)) verifier.SetHashSize(m_keyTemplate->m_signatureSize - m_keyTemplate->m_signatureKeySize); else verifier.SetHashSize(0); verifier.SetPublicKey(m_keyTemplate->m_verificationKey.get()); return verifier.Verify(signedData.GetBuffer(), (signedData.GetSize() + 7) >> 3, signature.GetBuffer(), (signature.GetSize() + 7) >> 3 , m_keyTemplate->m_signatureSize); } void QueryKeyData(const char * fieldName, void * buf, int * len) { m_keyData.Get(fieldName, buf, len); } int QueryIntKeyData(const char * fieldName) { return m_keyData.GetInt(fieldName); } void QueryDateKeyData(const char * fieldName, int * year, int * month, int * day) { m_keyData.GetDate(fieldName, year, month, day); } void QueryValidationData(const char * fieldName, void * buf, int * len) { return m_validationData.Get(fieldName, buf, len); } public: const LicenseTemplateImpl* m_keyTemplate; BitStruct m_keyData; BitStruct m_validationData; };