123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- import { Injectable } from "@angular/core";
- import { TwitterApiProvider } from "../twitter-api/twitter-api";
- import { P2pStorageIpfsProvider } from "../p2p-storage-ipfs/p2p-storage-ipfs";
- import { P2pDatabaseGunProvider } from "../../providers/p2p-database-gun/p2p-database-gun";
- import { Storage } from "@ionic/storage";
- import NodeRSA from "node-rsa";
- import * as openpgp from 'openpgp';
- declare var TextDecoder: any;
- declare var TextEncoder: any;
- @Injectable()
- export class CryptoProvider {
- ownUserId: string;
- IV_LENGTH = 12;
- HYBRID_OSN_AES_KEY = "Z1vxAULQnZdoWhJOvv+hWEvVpyUHzNjD/ichEE2c8i4=";
- email: string;
- constructor(
- private twitter: TwitterApiProvider,
- private ipfs: P2pStorageIpfsProvider,
- private storage: Storage,
- private gun: P2pDatabaseGunProvider
- ) {
- this.init();
- }
- private async init() {
- this.ownUserId = await this.storage.get("userId");
- this.email = await this.storage.get("email");
- }
- /**
- * Publishs the public key history with the latest key
- * @param key key to publish
- */
- public async publishPrivateKey(key: string) {
- let privateKeyHistory = await this.getKeyHistory(this.ownUserId);
- console.log("get publishPrivateKey crypto ", privateKeyHistory);
- // Todo: avoid publishing the same public key twice - check if new key equals newest key in history
- if ( key === privateKeyHistory[0])
- {
- return;
- }
- else
- {
- // Add new key to history
- const newKey = {
- key: key,
- validFrom: Date.now()
- };
- if (privateKeyHistory) {
- privateKeyHistory["keys"].push(newKey);
- } else {
- privateKeyHistory = {
- keys: [newKey]
- };
- }
- }
-
- // Ecnrypt key history
- const encryptedPrivateKeyHistory = JSON.stringify(privateKeyHistory);
- // Publish updated key history...
- const res = await this.ipfs.storePrivateKey(encryptedPrivateKeyHistory);
- // store ipfs link Of private tweet in gundb
- // let ipfsLink = "ipfs://" + res["Hash"];
- await this.gun.storePrivateKeyHistory(this.ownUserId, this.email, res["Hash"]);
- }
- public async getKeyHistory(userId: string) {
-
- //get private key history from gun
- let link = await this.gun.getPvtKeyHistory(userId);
- console.log("get link crypto ", link);
- // Fetch public key history
- if (link.length) {
- const encryptedKeyHistory = await this.ipfs.fetchJson(link);
- console.log("get link private key crypto ", encryptedKeyHistory);
- return JSON.parse(encryptedKeyHistory.toString());
- } else {
- return null;
- }
- }
- private extractTweetId(text: string): string {
- for (let word of text.split(" ")) {
- if (this.isTweetId(word)) {
- return word.substr(8);
- }
- }
- return "";
- }
- private extractLinkFromDescription(text: string): string {
- for (let word of text.split(" ")) {
- if (this.isIpfsLink(word)) {
- return word.substr(7);
- }
- }
- return "";
- }
- private isIpfsLink(word: string): boolean {
- return /ipfs:\/\/Qm[a-zA-Z0-9]+/.test(word);
- }
- private isTweetId(word: string): boolean {
- return /tweet:\/\/[0-9]+/.test(word);
- }
- /**
- * Generates a RSA key pair object
- */
- public async generateRsaKeys() {
- return await crypto.subtle.generateKey({
- name: "RSA-OAEP",
- modulusLength: 1024,
- publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
- hash: { name: "SHA-256" }
- },
- true,
- ["encrypt", "decrypt"]
- );
- }
- public async generatePgpKeys(email) {
- let options = {
- userIds: [{ name: 'Rohithosn', email: email }], // multiple user IDs
- curve: "ed25519", // ECC curve name
- passphrase: "This is phas" // protects the private key
- };
- let a = await openpgp.generateKey(options);
- return a;
- }
- /**
- * extracts the private key from the key object and transforms it to readable text
- * @param keys key object
- */
- public async extractPrivateKey(keys): Promise < string > {
- return btoa(
- String.fromCharCode.apply(
- null,
- new Uint8Array(await crypto.subtle.exportKey("pkcs8", keys.privateKey))
- )
- );
- }
- /**
- * extracts the public key from the key object and transforms it to readable text
- * @param keys key object
- */
- public async extractPublicKey(keys): Promise < string > {
- return btoa(
- String.fromCharCode.apply(
- null,
- new Uint8Array(await crypto.subtle.exportKey("spki", keys.publicKey))
- )
- );
- }
- /**
- * checks if the latest published key is the same as the one saved in app settings
- */
- public async isPublicKeyPublished(): Promise < boolean > {
- const publicKey = await this.storage.get("publicKey");
- return publicKey?true:false;
- }
- /**
- * checks if a private key is already set
- */
- public async isPrivateKeySet(): Promise < boolean > {
- const privateKey = await this.storage.get("privateKey");
- return privateKey?true:false;
- }
- /**
- * Encrypt text with RSA
- * @param plainText plain text
- * @param privateKey private key
- */
- public encrypt(plainText: string, privateKey: string) {
- const key = new NodeRSA(
- `-----BEGIN PRIVATE KEY-----${privateKey}-----END PRIVATE KEY-----`
- );
- return key.encryptPrivate(plainText, "base64");
- }
- /**
- * Decrypt secret with RSA
- * @param encryptedMessage encrypted message
- * @param publicKey public key
- */
- public decrypt(encryptedMessage: string, publicKey: string): string {
- const key = new NodeRSA(
- `-----BEGIN PUBLIC KEY-----${publicKey}-----END PUBLIC KEY-----`
- );
- return key.decryptPublic(encryptedMessage).toString();
- }
- /**
- * Fetches the public key history for a given user id
- * @param userId user id
- */
- public async fetchPublicKeyHistoryForUser(userId: string): Promise < object[] > {
- const keyHistory = await this.getKeyHistory(userId);
- return keyHistory["keys"].reverse();
- }
- private async aesEncrypt(plainText: string) {
- const utf8BytesOfPlainText = new TextEncoder().encode(plainText);
- const iv = crypto.getRandomValues(new Uint8Array(this.IV_LENGTH));
- const keyBytes = this.base64ToBytes(this.HYBRID_OSN_AES_KEY);
- const algorithm = { name: "AES-GCM", iv, length: 256 };
- return crypto.subtle
- .importKey("raw", keyBytes, algorithm, false, ["encrypt"])
- .then((cryptoKey: CryptoKey) => {
- return crypto.subtle.encrypt(
- algorithm,
- cryptoKey,
- utf8BytesOfPlainText
- );
- })
- .then((encData: ArrayBuffer) =>
- this.mergeBytes(iv, this.bufferToBytes(encData))
- )
- .then(this.bytesToBase64);
- }
- private aesDecrypt(encryptedMessage: string) {
- try {
- const ivWithEncryptedBytes = this.base64ToBytes(encryptedMessage);
- const { encryptedBytes, ivBytes } = this.splitIvAndEncrypted(
- ivWithEncryptedBytes
- );
- const keyBytes = this.base64ToBytes(this.HYBRID_OSN_AES_KEY);
- const algorithm = { name: "AES-GCM", iv: ivBytes, length: 256 };
- return crypto.subtle
- .importKey("raw", keyBytes, algorithm, false, ["decrypt"])
- .then((cryptoKey: CryptoKey) => {
- return crypto.subtle.decrypt(algorithm, cryptoKey, encryptedBytes);
- })
- .then((decryptedData: ArrayBuffer) => {
- return new TextDecoder().decode(decryptedData);
- });
- } catch (e) {
- return Promise.reject(e);
- }
- }
- private bufferToBytes(arrayBuffer: ArrayBuffer) {
- return new Uint8Array(arrayBuffer);
- }
- private bytesToBase64(bytes: Uint8Array): string {
- let binary = "";
- const len = bytes.length;
- for (let i = 0; i < len; i++) {
- binary += String.fromCharCode(bytes[i]);
- }
- return btoa(binary);
- }
- private base64ToBytes(base64: string): Uint8Array {
- const binaryString = atob(base64);
- const len = binaryString.length;
- const bytes = new Uint8Array(len);
- for (let i = 0; i < len; i++) {
- bytes[i] = binaryString.charCodeAt(i);
- }
- return bytes;
- }
- private mergeBytes(a: Uint8Array, b: Uint8Array) {
- const aLen = a.length;
- const bLen = b.length;
- const res = new Uint8Array(aLen + bLen);
- for (let i = 0; i < aLen; i++) {
- res[i] = a[i];
- }
- for (let i = 0; i < bLen; i++) {
- res[i + aLen] = b[i];
- }
- return res;
- }
- private splitIvAndEncrypted(ivWithEncryptedBytes: Uint8Array) {
- const dataLen = ivWithEncryptedBytes.length;
- const ivBytes = new Uint8Array(this.IV_LENGTH);
- const encryptedBytes = new Uint8Array(dataLen - this.IV_LENGTH);
- for (let i = 0; i < this.IV_LENGTH; i++) {
- ivBytes[i] = ivWithEncryptedBytes[i];
- }
- for (let i = this.IV_LENGTH; i < dataLen; i++) {
- encryptedBytes[i - this.IV_LENGTH] = ivWithEncryptedBytes[i];
- }
- return { ivBytes, encryptedBytes };
- }
- }
|