Encryption with Ionic

Hi All,

I am looking to implement Encrypt/Decrypt functionality in my Ionic 2 app. I am looking for something simple, that will work with Ionic 2.

Please can anyone recommend a library/plugin that works with Ionic 2?

I have tried a few libraries, but cannot get them to work in Ionic 2. I have issues with the import into Ionic 2.

E.g.

js-jose

Crypto-js
http://stackoverflow.com/questions/40467395/javascript-library-of-crypto-standards-implementation

1 Like

I use this library. And follow this tutorial.

Usage in ionic:

  1. In terminal in project root folder npm install --save jsencrypt
  2. In src/declarations.d.ts (maybe in your project this file located in other place) add line
declare module 'jsencrypt'
  1. And use library in service (I need only encrypt method in my project)
'use strict';

import Encrypt from 'jsencrypt';
import { Injectable } from '@angular/core';

@Injectable()
export class EncryptionService {
    private pem: string = `your_key`;

    public create(name: string): string {
        let encrypt = new Encrypt.JSEncrypt();
        encrypt.setPublicKey(this.pem);
        return encrypt.encrypt(name);
    };
}

P.S: also you can import and use any other third party library by following this 3 steps.

3 Likes

Hi snikh, thanks for the advise.

I am however, having problems setting up my src/declarations.d.ts file. I do not have a src folder or a declarations.d.ts file in my project.

Do you know if I should create one? If so, where should I place it in my folder structure? Id there anything else that needs to know about the src/declarations.d.ts file in order to register it?

enter image description here

After adding src/declarations.d.ts to the root of my project, I get:

ERROR in ./app/pages/service/personService.ts
(2,21): error TS2307: Cannot find module 'jsencrypt'.

for the following line:

import Encrypt from 'jsencrypt';

Iā€™m not sure, but maybe you use an old version of ionic framework with new version of ionic CLI (framework and CLI canā€™t work on different version. Latest CLI (2.1.4) work with ionic 2.0.0-rc0 and higher).
You can check your version by ionic info in terminal in root folder of your project. If framework version lover than 2.0.0-rc0 you need to update your project and fix all breaking changes.
Also you need local typescript 2+ in your project.

1 Like

Thanks.

I am using the following:

Your system information:

Cordova CLI: 6.4.0
Ionic Framework Version: 2.0.0-beta.11
Ionic CLI Version: 2.1.0
Ionic App Lib Version: 2.0.0-beta.20
OS:
Node Version: v6.2.2

But I am scared if I try upgrade to the latest version2.0.0-rc.2 (2016-11-03), other things in my app will break. So I will look for another encryption tool.

Thanks though.

I spent a week to upgrade my app from beta-11 to rc0 :sweat_smile:

In beta-11:

  1. Copy to your service folder jsencrypt.min.js from here.
  2. Use service:
'use strict';

var Encrypt = require('./jsencrypt.min');
import {Injectable} from '@angular/core';

@Injectable()
export class EncryptionService {
    private pem: string = `your_key`;

    constructor() {}

    public create(name: string): string {
        var encrypt = new Encrypt.JSEncrypt();
        encrypt.setPublicKey(this.pem);
        return encrypt.encrypt(name);
    };
}
2 Likes

Thank you, I really appreciate your help. As you can tell, I am pretty new to this.

I try what you suggest above, but I get the following error:

ERROR in ./app/pages/service/personService.ts
(2,15): error TS2304: Cannot find name 'require'.

I have noticed a lot of examples use require, but I am not sure why I get this error.

Do I need to upgrade to a higher version of Typescript?

tsc -v
Version 2.0.8

But when I run, it says I am using version 1.8.10:

ionic serve

ts-loader: Using typescript@1.8.10 and E:\Development\IDE\ionic-apps\theWhoZoo\tsconfig.json

I downgraded my ts:

npm install -g typescript@1.8.10

and installed typings:

npm install typings -g --save-dev
typings install dt~node --save --global

It is now building and seems to be working I think.

see

I almost have it working. It builds and runs fine. But when I try encrypt or decrypt, it just returns false instead of the encrypted/decrypted value.

My code:

private initEncryption(): void {
    this.encrypter = new Encrypt.JSEncrypt();
    this.rsa_key = 'myKey';
    this.encrypter.setPublicKey(this.rsa_key);
}

private encrypt(value: string): Promise<string> {
    console.log('encrypt1: ', value, this.encrypter);
    return new Promise<string>(resolve => {
        let encryptedValue = this.encrypter.encrypt(value);
        console.log('encrypt2: ', encryptedValue, value);
        if (!encryptedValue) {
            resolve(value);
        } else {
            resolve(encryptedValue);
        }
    });
}

jsencrypt.js

JSEncrypt.prototype.encrypt = function (string) {
    // Return the encrypted string.
    try {
        console.log(this.getKey());
        return hex2b64(this.getKey().encrypt(string));
    }
    catch (ex) {
        console.error(ex);
        return false;
    }
};

output:

encrypt1: password1 Object { default_key_size=1024,  default_public_exponent="010001",  log=false,  more...}
Object { e=0,  n=null,  d=null,  more...}
TypeError: this.n is null
encrypt2: false password1

So it looks like the problem is in the this.getKey() function of jsencrypt.js.

Is this because I have initialized it incorrectly?

Maybe your this.rsa_key is wrong.

Try console.log(Encrypt) for check correct initialization of encryption module.

Yes it looks like it is the key that is the problem:

private rsa_key: string = null;
private encrypter: any = null;

private initEncryption(): void {
    this.encrypter = new Encrypt.JSEncrypt();
    this.rsa_key = 'myKey';
    this.encrypter.setPublicKey(this.rsa_key);
    console.log(this.encrypter);
}

output:

enter image description here

The key has null values.

But I am not sure what I have done wrong?

FIXED:

The problem was with the key, it cannot just be 'myKey' it looks like. The following works:

private initEncryption(): void {
    console.log('initEncryption') 
    this.encrypter = new Encrypt.JSEncrypt();
    this.rsa_key = 'MIICXgIBAAKBgQDHikastc8+I81zCg/qWW8dMr8mqvXQ3qbPAmu0RjxoZVI47tvs'+
                    'kYlFAXOf0sPrhO2nUuooJngnHV0639iTTEYG1vckNaW2R6U5QTdQ5Rq5u+uV3pMk'+
                    '7w7Vs4n3urQ6jnqt2rTXbC1DNa/PFeAZatbf7ffBBy0IGO0zc128IshYcwIDAQAB'+
                    'AoGBALTNl2JxTvq4SDW/3VH0fZkQXWH1MM10oeMbB2qO5beWb11FGaOO77nGKfWc'+
                    'bYgfp5Ogrql4yhBvLAXnxH8bcqqwORtFhlyV68U1y4R+8WxDNh0aevxH8hRS/1X5'+
                    '031DJm1JlU0E+vStiktN0tC3ebH5hE+1OxbIHSZ+WOWLYX7JAkEA5uigRgKp8ScG'+
                    'auUijvdOLZIhHWq7y5Wz+nOHUuDw8P7wOTKU34QJAoWEe771p9Pf/GTA/kr0BQnP'+
                    'QvWUDxGzJwJBAN05C6krwPeryFKrKtjOGJIniIoY72wRnoNcdEEs3HDRhf48YWFo'+
                    'riRbZylzzzNFy/gmzT6XJQTfktGqq+FZD9UCQGIJaGrxHJgfmpDuAhMzGsUsYtTr'+
                    'iRox0D1Iqa7dhE693t5aBG010OF6MLqdZA1CXrn5SRtuVVaCSLZEL/2J5UcCQQDA'+
                    'd3MXucNnN4NPuS/L9HMYJWD7lPoosaORcgyK77bSSNgk+u9WSjbH1uYIAIPSffUZ'+
                    'bti+jc1dUg5wb+aeZlgJAkEAurrpmpqj5vg087ZngKfFGR5rozDiTsK5DceTV97K'+
                    'a3Y+Nzl+XWTxDBWk4YPh2ZlKv402hZEfWBYxUDn5ZkH/bw==';
    this.encrypter.setPublicKey(this.rsa_key);
    console.log(Encrypt);
    console.log(this.encrypter);
}

I appreciate all your help here. You saved me a lot of time and pain, thank you.

I donā€™t want this to sound overly harsh, but if you are intending to distribute this app to anybody (i.e. if youā€™re not just using it as a personal learning experience), please please have the design done or at least audited by somebody who understands cryptographic protocols.

You do not want to be using naked RSA encryption for messages. You need to be using a padding scheme and key wrapping like OAEP. Designing cryptographic protocols is extremely hard, and even experts who know far more than either you or I make mistakes doing it. Donā€™t do it yourself. Use standards like JWE.

1 Like

Hi rapropos,

Itā€™s not harsh, itā€™s constructive criticism . Thank you for the advise.

Even though my requirements may appear simple to me (i.e. I am trying to hide the users password), as you are saying it is far more complex.

I donā€™t have much knowledge of secure systems . I think I need to do some more research and reading to try and understand. Unfortunately I donā€™t have access to a person who is knowledgeable in this area.

I tried to use https://github.com/square/js-jose, in order to use JWE, but had problems trying to import it into Ionic2. I think I will try again to make use of it.

Question
Is the main problem with using naked RSA encryption that the key is just sitting in the code exposed? That means anyone can access it to decrypt the ciphertext?

That is one problem. Whatever encryption algorithm you choose, storing hardcoded keys is a fatal flaw. Another is that RSA itself is not a suitable algorithm for directly encrypting messages. See here or other resources about padding.

I am committed to making the square js-jose library a best practice choice for ionic developers.

1 Like

Will any of these solutions work for encrypting and decrypting files that get downloaded/uploaded from/to a server?

Probably, but itā€™s hard to say more without more information about the workflow. Who is doing the encrypting and where, and who should be able to decrypt it and where? Do you want the server administrator to be able to read things, or do you specifically want that to be impossible?

Fair enough. Basically the idea will be this:

  1. Users will be presented a list of ā€œfilesā€, in which when they tap on that list item, it will download an encrypted file from an Amazon S3 bucket (AES256 preferred).

  2. Once the file is decrypted, letā€™s say itā€™s an mp4 file, that mp4 file would then be loaded into a <video> tag so that the user could then watch the video. This exact thing will applicable to any file types (pdf, mp3, docx, etc.)

That is pretty much it. There is actually no need to upload an encrypted file, only decrypt one that is downloaded from an Amazon S3 bucket.

Any thoughts? I havenā€™t seen a whole lot on this. Could Crypto-Js be a viable solution inside of an Ionic 2 app?

What is the purpose of the encryption? DRM so that the users must somehow acquire the key separately? In general, you could use AES-GCM (my preference) or AES-CBC. JWE supports direct encryption mode, where the key must be passed separately. Your keyserver could have a list of file URLs and the AES keys used to encrypt them. It could dispense them to authenticated users. The client app could then use the key to decode the JWE it downloaded from S3. I think js-jose could handle this in fairly straightforward fashion, and you could use it (or the sister Golang implementation) to create the encrypted documents on the server side. I would definitely recommend using JWE over rolling your own encrypted packaging system; it has gone through extensive peer review.

Ah this is very good. Thankyou for that. There were some new terms I needed to research. So with this being said, it looks like js-jose would be a good option. The next big question isā€¦since there doesnā€™t seem to be much documentation on how to import it into Angular 2, do you have any idea of the steps that would need to happen in order to be able to use it in an Ionic 2 app?

Which one would be ideal? https://www.npmjs.com/package/node-jose or
https://github.com/square/js-jose?

I know Angular 2 requires typings, so Iā€™m a little concerned with that as well.