Skip to Content
Technical Articles

Protect SAP Analytics Cloud Analytic Application Code from Illegal Copy

In this tutorial, we will learn how to protect your SAC Analytic Application code from the illegal distribution. Just keep in mind that nothing is unbreakable. This method just to add additional steps to prevent your code being distributed easily.  We’ll be using libSodium JS library and then obfuscate the code using obfuscator.io.

Here is the simple diagram that illustrates the mechanism.

Before the main function is executed, the app will check if is executed from the legitimate URL which is public SAP Analytics Cloud URL for your tenant.

Encryption

The encryption process will be done offline with the following steps:

 

Below is the code to get the random chiper based on the input key, phrase and random nonce.

<script src="sodium.js" async></script>
  <script>
    window.sodium = {
        onload: function (sodium) {
			try {

				let key = 'C06BFAFD06A8158368CF537650C934F3';
				let phrase = 'https://xxx.us10.sapanalytics.cloud/sap/fpa/ui/tenants/yyyy';

				let h = sodium.crypto_generichash(32, sodium.from_string(key));
				key = sodium.from_hex(sodium.to_hex(h)); 

				let nonce = sodium.randombytes_buf(24);
				console.log('nonce: ' + sodium.to_hex(nonce));

				let encrypt = sodium.crypto_secretbox_easy(phrase, nonce, key)
				console.log('ciphertext: ' + sodium.to_hex(encrypt));			}
			catch(err) {
				console.log(err);
			}
        }
    };
</script>

Decryption

The decryption process will be done in Analytic App with the following steps:

  • Inputs are random chiper, random nonce and key.
  • Decrypt using these inputs.
  • Check the result against phrase. If the result is valid then execute the main function.

The key, random nonce and random chiper are revealed in Analytic App code. We need to obfuscate the code to make it harder for others to get this information. As mentioned, we need to keep the key secret, otherwise with these information, we can reverse the process and get the desired phrase.

Finally, the phrase will be checked against the actual phrase which is the public SAP Analytics Cloud URL for your tenant with tenant ID. If the information is not matched, we throw an unauthorized message.

Below code is to get the key from the App ID and actual phrase from Tenant URL and loads the libSodium library to perform the decryption. If the result is matched then calls the main function loadthis().

onCustomWidgetAfterUpdate(changedProperties) {
    var that = this;

    // try detect runtime settings
    if (window.sap && sap.fpa && sap.fpa.ui && sap.fpa.ui.infra) {
        if (sap.fpa.ui.infra.common) {
            let context = sap.fpa.ui.infra.common.getContext();
            appid = context.getAppArgument();
        }
        if (sap.fpa.ui.infra.service && sap.fpa.ui.infra.service.AjaxHelper) {
            tenant_URL = sap.fpa.ui.infra.service.AjaxHelper.getTenantUrl(false); // true for PUBLIC_FQDN
        }
        if (this._firstConnection === 0) {
            let sodiumjs = "http://localhost/SAC/sacsodium/sodium.js";
            async function LoadLibs() {
                try {
                    await loadScript(sodiumjs, _shadowRoot);
                } catch (e) {
                    alert(e);
                } finally {

                    if (await sodium.ready.then(sodiumInitialized).catch(sodiumNotInitialized) === tenant_URL) {
                        loadthis(that, changedProperties);
                    } else {
                        console.log("Unauthorized");
                        alert("Unauthorized");
                    }
                }
            }
            LoadLibs();
        }
    }
}

This function sodiumInitialized(), performs the decryption process and returns the result.

function sodiumInitialized() {
    return new Promise(function(resolve, reject) {
        try {
            let nonce = new Uint8Array(sodium.from_hex('19e6ecf17e866ff0cab830415f98abda9c69b17fb75cb84d'));
            let ciphertext = new Uint8Array(sodium.from_hex('a1cb24aff6b92c6cc89026478d093a96fd60b257d5946dbx14464d3c638bcc6f53694191985c1d9839795142069b4ff8f44497d9f40f3d3b448b28ebfd08794b4b1175c2d67e43980cfee4d3b0f33f8f4183d8bb'));
            let decrypt = sodium.crypto_secretbox_open_easy(ciphertext, nonce, sodium.from_hex(sodium.to_hex(sodium.crypto_generichash(32, sodium.from_string(appid.appId))))) //Key should be kept secret
            resolve(sodium.to_string(decrypt));
        } catch (err) {
            console.log(err);
            resolve('err');
        }
    });
}

Obfuscation

We will use obfuscate tool from obfuscator.io.

 

Use this option to obfuscate the code with debug protection.

The output will makes the code harder to read.

That’s all. I hope with this simple technique, you can build your app more harder to be stolen and copied.

References

2 Comments
You must be Logged on to comment or reply to a post.