I am setting up a licensing backend with Python and thought I might add my experiences here. My first attempts failed unfortunately; Spirux’ Python3 package didn’t work on Mac Sonoma. I might have gotten matkat’s RSA juce extension to work, but then the issue was encrypting something in Python with a private key which isn’t supported by the current standard cryptography package because apparently you aren’t supposed to do that
Long story short I ended up implementing the “applyToValue” function in Python:
def apply_to_value(value, key_part1, key_part2):
result = 0
part1 = int(key_part1, 16)
part2 = int(key_part2, 16)
if part1 == 0 or part2 == 0 or value <= 0:
return result
while value != 0:
result = result * part2
div, mod = divmod(value, part2)
value = div
result = result + pow(mod, part1, part2)
return result
# Will only work for JUCE RSA cryptography
def generate_activation_token(xml_string, private_key_pem):
xml_numeric = int.from_bytes((xml_string[::-1]).encode('utf-8'), byteorder='big')
private_key_split = private_key_pem.split(',')
key_part1 = private_key_split[0]
key_part2 = private_key_split[1]
signature = apply_to_value(xml_numeric, key_part1, key_part2)
return format(signature, 'x') # convert signature (which is int) to signature_string of base 16
# Usage
some_string = "Lorem ipsum quia dolor sit amet"
private_key = "1a9b694004ff3b81,85090e41987a14c9" # Throwaway key (64 bit in this case)
encrypted_string = generate_activation_token(some_string, private_key)
print(encrypted_string)
In C++, this could the encrypted_string could then be decrypted like this:
juce::RSAKey publicKey("5,85090e41987a14c9");
juce::String encryptedString = "13cc53ec14c480ef8251bea55d7c1d1393cf88b9ac960b8258c772fc0184a57"; // Output from Python
// The following code was more or less copied from decryptXML in juce:OnlineUnlockStatus
juce::BigInteger val;
val.parseString (encryptedString, 16);
juce::RSAKey key (publicKey);
jassert (key.isValid());
std::unique_ptr<juce::XmlElement> xml;
if (! val.isZero())
{
key.applyToValue (val);
auto mb = val.toMemoryBlock();
if (juce::CharPointer_UTF8::isValidString (static_cast<const char*> (mb.getData()), (int) mb.getSize()))
{
std::cout << "Success:" << mb.toString() << std::endl;
} else {
std::cout << "Failure" << std::endl;}
}
I have also found success with using the output directly in
KeyFileUtils::getDataFromKeyFile (KeyFileUtils::getXmlFromKeyFile (licenseTokenFromDisk, publicKey));
assuming of course the encryptedString is a single-line XML key file.