afAxonatorExt icon

afAxonatorExt

Encrypts and obfuscates Axon source code (for SkySpark 3.0.x only)
afAxonatorExt

Registered StackHub users may elect to receive email notifications whenever a new package version is released or a comment is posted on the forum.

There are 6 watchers.

v1.0.8

An extension for SkySpark v3.0.x that encrypts Axon source code.

This extension has been superseded by Axon Encryptor.

Axon functions can be distributed to clients and customers in Trio files. This is great until you realise Trio is a plain text format and what you're actually doing is distributing your Axon source code in plain sight!

This allows anyone to copy your hard work and potentially steal your intellectual property.

Even if you distribute your functions in .pod files, the Axon source code is still exposed through plain text Trio files in the pod.

Until now - encrypt and protect your Axon code with Axonator!

Axonator Logo

Axonator encrypts your Axon source code, creating drop-in replacement functions.

Try the new front-end for Axonator!

Axonator is free to download and evaluate but a licence must be purchased for production use. See Licensing for details.

Overview

Axonator takes plain text Axon source code and a pass phrase, and generates encrypted Axon code and a secret key. The encrypted code can only be executed and run with the secret key.

For example, Axonator takes Axon source code in plain text like this:

(name) => do
  return "Hello " + name + "!"
end

and encrypts it into code like this:

(name) => do
  axonCode :
    "AxD:mvUjtIFWCMNZV1HuOAxMMg::jc84ZwXVBPzw3vfg2rLl1NIZx8eemoG_pYZEnnZfSvYZElURNjU4" +
    "c62cfYTMHGMf2HFsjYn0V8Kagb8hj8nBN9lkRUryYUxojI6zuWCnNef1LIqJ7fDdwcC43dpXsMunsHH_" +
    "6U7eKhTxJWzF0A32SLsdnotcjOwOyRKfUI91n-QHma9mEi2Ri4mRhGW805ISTU5Ut_LiwdImXL-qnqHQ" +
    "FUuWwiV-53ZSFnyUi_uAybEJBxNbiFiSRSptuTsrO5SQd6Np2V4iGM25b0Rc_WRP09LYbuo4Qo0w_Dqu" +
    "hvpRSpzGJzo1nBrEKtViI3T9j6R3RLTkXkwi8Jqp6kuJhjERyQ"
  keyFunc : (fnName) => ... fn that returns a secret key ...
  return axonatorCallFunc("hello", axonCode, [name], keyFunc)
end

Axonator can encrypt an individual function record, a Trio file of functions, or even an entire directory of Trio function files!

Axonator never reveals the decrypted / original Axon source so you can be confident your intellectual property remains safe.

The encrypted functions and Trio files are direct drop in replacements for the original. So if distributing Axon functions via .pod files, you would encrypt your Axon source files and distribute the axonated version in place of the original.

Quick Start

AxonatorUI is the easiest way to use Axonator and see the encryption in action. But if you're happy with raw Axon scripting, then read on...

Here's how to encrypt an Axon function:

// Axon funcs may be any created with the SkySpark Func app
// but here we're just going to create one in code
plainFuncRec : {
    func,
    "name" : "hello",
    "src"  : """(name) => "Hello " + name + "!" """
}

// encrypt the function
passPhrase : "Axonator Protects"
axonated   : axonateFunc(plainFuncRec, passPhrase)

// this is the encrypted func record
encryptedFuncRec : axonated["funcRec"]

// print the encrypted Axon source to the console
echo( encryptedFuncRec["src"] )

The encrypted source code may then be compiled and run, just like any other Axon function:

// compile the encrypted code...
helloFn : encryptedFuncRec["src"].eval()

// ...and run it!
helloFn("Mum")  // --> "Hello Mum!"

Key Functions

From the last example, note the secret key from the returned axonated Dict:

// keep this safe!
secretKey : axonated["secretKey"]  // --> "pPLFy7m5L5ym-WaVY9wiAQ"

The secret key is what Axonator needs to execute the axonated code.

To obtain the secret key, Axonator requires a keyFunc that returns the secret key when executed. You can see the keyFunc in the encrypted code from the last example:

(name) => do
  axonCode :
    "AxD:paWD-OWysOhmOg7h9VKf3Q::Zyp3EtWBS7hR3pEMXd7Odpr40jY_x6baLvvMSYi-iNVwj86xTpfF" +
    "h8H56DLHH1Jnte6SkiZZSxvch3mQxbGRDMizoR34xJV560q5fiTe8nWb9YZR2gLh5bKXhQHBuCqVD1Yp" +
    "nDnwOkWnT3rhvRt6B_5AQqV-4qisw_xtIhQ0HRIWtJLjFcp5O9U0PeTIW2TcJgb1u_um-cXb55PoI-iw" +
    "f4FVZrNy6NKkoQM126XRwX5ARXLpXnatlxQfsUftRSNz0jeBL9NABHc0-N2zWjJsbO6QvGpcBXduKjke" +
    "bD2RAyDm2LerHPCSKFqu4ATIelR4bJbbSfTXyom0BqnFH37XcQ"

  keyFunc : () => "pPLFy7m5L5ym-WaVY9wiAQ"

  return axonatorCallFunc("hello", axonCode, [name], keyFunc)
end

The simplest keyFunc is one that just returns the secret key in plain text. And indeed, from the code above you can see that is what Axonator does by default. Whilst not 100% secure (see Notes on Security) it is extremely obfuscated and is usually good enough for most use cases.

Custom KeyFuncs

KeyFuncs take the function name as an optional argument, this lets you use another Axon function to perform a look up for the secret key.

This allows for highly customisable keyFuncs that are able to retrieve the secret key from a REST API, a StackHub licence file, or anywhere!

To use a custom keyFunc in axonated code, pass the keyFunc source code to one of the axonate functions:

funcRec    : ...
keyFunc    : "(fnName) => lookUpSecretKey(fnName)"
passPhrase : "Axonator Protects"
axonated   : axonateFunc(funcRec, passPhrase, keyFunc)

To customise keyFuncs even further, an Axon Fn may be passed to the axonate methods:

funcRec    : ...
keyFunc    : (fnName, secretKey) => "(fnName) => lookUpSecretKey(\"" + fnName + "\")"
passPhrase : "Axonator Protects"
axonated   : axonateFunc(funcRec, passPhrase, keyFunc)

The Axon Fn must return a string to be used as the keyFunc.

StackHub KeyFuncs

Create a product on StackHub and use its packge name to create a keyFunc, then use the keyFunc to encrypt your Axon functions:

// create a keyFunc with our pacakge details
packageVer : "acmeAwesome 2.3"
keyFunc    : axonatorStackHubKeyFunc("package", packageVer)

// these following lines are the same as usual
passPhrase : "Axonator Protects"
axonated   : axonateFile(`io/funcs.trio`, passPhrase, keyFunc)
secretKey  : axonated["secretKey"]
               // --> pPLFy7m5L5ym-WaVY9wiAQ

Note the secret key and edit your StackHub product to add the following extra property:

axonatorKey = <secretKey>

which, in our example, would be:

axonatorKey = pPLFy7m5L5ym-WaVY9wiAQ

When a licence file is generated for your product, it will contain the above property, meaning the only people with access to the secret key are those who have a valid licence file.

If you look at your encrypted Axon functions, the keyFunc will look similar to this:

keyFunc : () => axonatorGetKeyFromStackubLic("package", "acmeAwesome 2.3", "xxxxxxxx")

This generated keyFunc calls a hidden function that looks for a StackHub licence that matches the package acmeAwesome 2.3. If such a licence is found, and if the licence is valid, the function returns the axonatorKey property, which is the secret key you setup earlier!

This means that only people with a valid StackHub generated licence have access to the secret key, and only people with a valid StackHub generated licence can run your Axon functions.

All functions encrypted with the axonatorStackHubKeyFunc key func are unrestricted, making Axonator FREE for creating StackHub products.

Note: Be careful when there's a different number of version segments in the StackHub licence and in the key func. Lobby the Fantom post sys::Depend.match() anomaly for a fix.

Command Line Encryption

Axonator may be invoked from the command line to encrypt .trio files. This is useful if you wish to encrypt many files in a batch, or in a non-SkySpark environment.

The examples below have new lines added for clarity.

Use Axonator with a valid Axonator licence and custom key func:

fan afAxonatorExt
    -axonIn      lib/myFuncs.trio
    -axonOut     lib/myEncyptedFuncs.trio
    -passPhrase  "Axonator Protects"
    -skysparkLic lic/lic-skyspark.props
    -axonatorLic lic/lic-axonator.props
    -keyFunc     "(fnName) => return \"gm8v8MePNgSRhVRZ-2zogw\""

To use Axonator in evaluation mode, just omit the licences:

fan afAxonatorExt
    -axonIn      lib/myFuncs.trio
    -axonOut     lib/myEncyptedFuncs.trio
    -passPhrase  "Axonator Protects"
    -keyFunc     "(fnName) => return \"gm8v8MePNgSRhVRZ-2zogw\""

To encrypt a directory of function files, just pass in the input / output directories:

fan afAxonatorExt
    -axonIn      lib-axonIn/
    -axonOut     lib-axonOut/
    -passPhrase  "Axonator Protects"
    -keyFunc     "(fnName) => return \"gm8v8MePNgSRhVRZ-2zogw\""

Note for Windows users: You should also use /forward slashes/ in directory names, as per the examples above.

Use the -help option for details:

fan afAxonatorExt -help

Notes on Security

Axonator encrypts using the Advanced Encryption Standard; which is pretty strong.

Note that export laws in the United States prohibit Oracle from selling very strong encryption. This limits the encryption strength of the standard Java installation, and hence Axonator, to 128 bits. Stronger encryption is possible in Java but requires the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy to be installed.

Running Axonated functions require the use of a secret key. While Axonator itself does not reveal the original Axon source code, anyone with the secret key (including the end user) and enough programming knowledge may be able to reveal the original Axon code.

For this reason, source code encrypted with Axonator should not be considered secure and Axonator itself should be considered an obfuscater. The only way to truly keep your functions secure, is to not distribute them in the first place.

Licensing

Axonator is a Commercial product and requires a licence to be purchased (see below) to run unhindered.

One Axonator licence will enable unlimited encryption on a single instance of SkySpark. You will need to enter your SkySpark licence ID when purchasing, see Where is my SkyArc License ID? for details.

Purchased licences expire after 1 year. After this period all previously encrypted functions will continue to work as usual, but a new valid licence will be required to encrypt further functions.

Purchased licences are available from the My Licences page and should be downloaded to the /var/lic/ directory of your SkySpark installation.

Minor updates to Axonator may be provided free of charge, but major updates will require a new licence to be purchased.

Although free to download, Axonator enters into an Evaluation Mode if it does not find a valid licence; whereby encrypted functions may only be invoked a maximum of 5 times and expire after 1 day.

Use of this software is bound the terms of the End User Licence Agreement (EULA) which can be found within the software download.

For support, please email ----------------------.

SkyPosium Presentation

A presentation entitled Protect Your Code With Axonator was given to the SkyFoundry SkyPosium event in Dulles, Virginia, USA on Thursday, 15th November 2017.

FAQs

How do I encrypt a Trio file?

A Trio file of Axon functions may be encrypted via axonateFile:

passPhrase : "Axonator Protects"
axonateFile(`io/funcs.trio`, passPhrase)

axonateFile backs up your .trio file and replaces it with a version where all the src tags have been encrypted. All other tags and non-func records remain intact hence the encrypted file may be used in place of the original.

Note you should always keep a copy of your original .trio files as they can not be restored.

How do I see the decrypted Axon source code?

You cannot. Axonator never reveals the decrypted Axon source. To do so represents a security risk.

Make sure you keep your source backed up!

Does Axonator impact on function performance?

The performance impact of using Axonator should be negligible.

There may be a very small delay the first time an axonated function is called due to the execution and compilation process, but once processed, Axonator caches a reference to the compiled Axon function.

All subsequent calls to the function are routed straight through to the cached compiled version. So any performance hit is only ever taken once; after that, your function performs just as fast as the un-axonated version.

When distributing encrypted functions to clients, do they also need Axonator?

Yes. The Axonator extension is used to execute your functions, so clients will need it on their SkyArc installations.

Fortunately, the SkySpark Install Manager can download and install Axonator automatically when it downloads your pod from StackHub. To enable this, do the following:

Axon Pods

If your .pod only contains Axon functions and other resources, and has no Fantom code, then add the following lines to your meta.props file:

...
pod.depends=afAxonatorExt 0.9-1.0
ext.depends=afAxonator
...

If your meta.props already defines these properties, then Axonator values may be appended like this:

...
pod.depends=sys 1.0; afAxonatorExt 0.9-1.0
ext.depends=weather, afAxonator
...

Note how one property separates values with a semi-colon and the other with a comma.

The pod.depends value lets the SkySpark Install Manager know it should download and install Axonator along with your extension, and the ext.depends value lets the SkySpark Extension Manager know it should enable Axonator when it enables your extension.

See Resource Extensions in the SkySpark documentation for details.

Fantom Pods

If you are distributing your functions in a Fantom .pod file then your build.fan should express a dependency on afAxonatorExt. This will make sure Axonator is installed on any target system. It also lets SkySpark Install Manager know it should download and install Axonator automatically along with your extension.

depends = [
    // ---- Fantom Core ----
    "sys           1.0.70 - 1.0",

    // ---- Axonator ----
    "afAxonatorExt 0.9.8  - 1.0",

    // ---- SkySpark ----
    "skyarcd       3.0.13 - 3.0",
    "haystack      3.0.13 - 3.0",
    "stackhub      3.0.13 - 3.0",
    ...
    ...
]

Your extension should also express a dependency on the afAxonator extension to make sure Axonator is enabled for your project.

using skyarcd::Ext
using skyarcd::ExtMeta

@ExtMeta {
    name    = "acmeAwesome";
    depends = Str["afAxonator"]
}
const class AwesomeExt : Ext {
  ...
}

Are defcomp functions supported?

As of SkySpark 3.0.21 Axon has new defcomp functions. While defcomp functions themselves cannot be encrypted, they are identified and ignored in the encryption process - meaning they won't cause any errors.

If you need to encrypt the contents of a defcomp function then it is advised to factor out the meat in to a standard Axon func which can be encrypted. Example:

defcomp
    inA: {is:^number, defVal:0}
    inB: {is:^number, defVal:0}
    out: {is:^number, readonly}
    do
        out = superSecretFunc(inA, inB)
    end
end

Where superSecretFunc is a standard Axon function that get encrypted. This way you get all the benefits of input parameter caching AND Axonator encryption!

Also see Are 'defcomp' functions supported?

How NOT to encrypt Axon functions

If encrypting .trio file of Axon code, sometimes you may want to leave some functions as they are, un-encrypted. Here's how...

When a function is axonated it is marked with an axonated tag. This lets Axonator know the function is already encrypted so it knows not to re-encrypt it again.

So if you have a Axon function that you do not want to axonate... say for instance, you have a .trio file of functions, but you need to keep one as plain text, then you can tag this function with axonated and Axonator will skip over it.

This is a little overloaded use of the axonated tag, so let me know if you use this heavily and I'll think about adding a specific tag just for this purpose.

Limitations

All Axon functions can be axonated including functions with default values, even if those default values contain Lists, Dicts, and other top-level function calls.

For a discussion on defcomp functions, see Are 'defcomp' functions supported?

SkySpark v3.0.21 (and below)

In earlier versions of SkySpark (v3.0.21 and below), due to the way they report function parameters, some knarly default values can cause problems; particularly Lists and Dicts nested with a function:

// This function signature is problematic
(a: (() => ["=>", "==>"].first)()) => do
    ...
end

Should you need such default parameters logic, it is best for Axonator (and your sanity!) to move it within the function:

// This function signature is fine
(a: null) => do
    if (a == null)
        a = (() => ["=>", "==>"].first)()
    ...
end

Disclaimer

The software is provided "AS IS" and the author disclaims all warranties with regard to this software including all implied warranties of merchantability and fitness. In no event shall the author be liable for any special, direct, indirect, or consequential damages or any damages whatsoever resulting from loss of use, data or profits, whether in an action of contract, negligence or other tortious action, arising out of or in connection with the use or performance of this software.

Published by Fantom Factory

Products & Services by Fantom Factory

Packages by Fantom Factory

Commercial packages

Free packages

Licensing options
Axon Encryptor
Encrypts and obfuscates Axon source code
1 year licence
$425.00USD
2 year licence
$800.00USD
Package details
Version1.0.8
LicenseCommercial
Build date4 years ago
on 17th Nov 2020
Requirements SkySpark v3.0.13
Depends on
File nameafAxonatorExt.pod
File size77.55 kB
MD55a1d000014886e896a0278826a32cb74
SHA1 9447428473242e91d5f1079f46ce62bc9cb98b68
Published by
Fantom FactoryDownload now
Also available via SkyArc Install Manager
Tags
Axon
Sky Spark
Fantom