Vue.jsで暗号化・復号化を実装する

  • Updated: 2024.06.25
  • Published: 2023.05.04
  • 584views

概要

下記githubのソースをもとにVue.js用にプラグイン化しました。

https://gist.github.com/Agoreddah/511864e2c00da064586523b3087c30e2


ソース

// load dependencies
const crypto = require('crypto');

'use strict';

const APP_KEY = 暗号化キー;

const SETTINGS = {
  key : Buffer.from(APP_KEY.substring(7), 'base64'),
  sha : 'sha256',
  mode : 'AES-256-CBC'
}

const Crypto = {
  install(Vue) {
    Vue.prototype.crypto = {
      /**
       * Caclulate MAC.
       * Paylod needs to be decoded to JSON with getJsonPayload(payload)
       * @param {Object} payload with iv & value
       * @param {String} key
       */
      calculateMac(payload, key){
        let hashedData = this.hash(payload['iv'], payload['value'])
        return this.hashHmac(hashedData, key);
      },
      /**
       * Decrypts payload with master key
       * @param {String} Payload - base64 encoded json with iv, value, mac information
       */
      decrypt(payload){
        if(payload !== ''){
          try {
            let _payload = this.getJsonPayload(payload);
            let _iv = Buffer.from(_payload['iv'], 'base64');
            let decipher = crypto.createDecipheriv(SETTINGS.mode, SETTINGS.key, _iv);
            let decrypted = decipher.update(_payload['value'], 'base64', 'utf8');
            decrypted += decipher.final('utf8');
            return this.hashDeserialize(decrypted);
          }catch (e) {
            return payload;
          }
        }else{
          return '';
        }
      },
      /**
       * Create payload encrypted with master key.
       * Payload contains: iv, value, mac
       * @param {String} data to be encrypted
       * @return {String} Base64 encdoded payload
       */
      encrypt(data){
        let serializedValue = this.hashSerialize(data);
        try{
          let _iv = crypto.randomBytes(16);
          let base64_iv = _iv.toString('base64');
          let cipher = crypto.createCipheriv(SETTINGS.mode, SETTINGS.key, _iv);
          let encrypted = cipher.update(serializedValue, 'utf8', 'base64');
          encrypted += cipher.final('base64');
          let _mac = this.hash(base64_iv, encrypted);

          let payloadObject = {
            'iv' : base64_iv,
            'value' : encrypted,
            'mac' : _mac
          }

          let _payload = JSON.stringify(payloadObject);
          return Buffer.from(_payload).toString('base64');
        }
        catch(e){
          throw new Error('Cannot encrypt data provided !');
        }
      },
      /**
       * Get JSON object from payload.
       * Payload needs to be base64 encoded and must contains iv, value, mac attributes.
       * MAC is validated
       * @param {String} payload
       * @return {Object} Data with iv, value, mac
       */
      getJsonPayload(payload){
        if(payload === undefined || payload === ''){
          throw new Error('Payload MUST NOT be empty !');
        }

        if(typeof payload !== 'string'){
          throw new Error('Payload MUST be string !');
        }

        try{
          this._payload = JSON.parse(Buffer.from(payload, 'base64'));
        }
        catch(e){
          throw new Error('Payload cannot be parsed !');
        }

        if(!this.isValidPayload(this._payload)){
          throw new Error('Payload is not valid !');
        }

        if(!this.isValidMac(this._payload)){
          throw new Error('Mac is not valid !!');
        }
        return this._payload;
      },
      /**
       * Hash function.
       * Combines initialization vector (iv) with data to be hashed (value).
       * Uses master key to hash results
       * @param {String} iv Initialization vector
       * @param {String} value Data
       */
      hash(iv, value){
        if(iv === undefined || iv === ''){
          throw new Error('Iv is not defined !');
        }
        if(value === undefined || value === ''){
          throw new Error('Value is not defined !');
        }
        let data = String(iv) + String(value);
        return this.hashHmac(data, SETTINGS.key);
      },
      /**
       * Crypto function to hash data with given key
       * @param {String} data
       * @param {String} key
       */
      hashHmac(data, key){
        let hmac = crypto.createHmac(SETTINGS.sha, key);
        hmac.update(data);
        return hmac.digest('hex');
      },
      /**
       * MAC validation function.
       * Payload must be decoded to JSON
       * @param {Object} payload
       */
      isValidMac(payload){
        let bytes = crypto.randomBytes(16),
          calculatedMac = this.calculateMac(payload, bytes);

        let originalMac = this.hashHmac(payload['mac'], bytes);
        return originalMac === calculatedMac;
      },
      /**
       * Payload validation function.
       * Payload must be decoded to JSON
       * @param {Object} payload
       */
      isValidPayload(payload){
        return (
          Object.prototype.hasOwnProperty.call(payload, "iv") &&
          Object.prototype.hasOwnProperty.call(payload, "value") &&
          Object.prototype.hasOwnProperty.call(payload, "mac")
        );
      },
      hashDeserialize(data) {
        let str = String(data)
        return str.substring(str.indexOf(':', 2) + 2, str.lastIndexOf(';') - 1)
      },
      hashSerialize(data){
        if(typeof data !== 'string'){
          throw new Error('Data to be serialized must be type of string !');
        }
        let str = String(data);
        return 's:'+str.length+':"'+str+'";';
      }

    }
  }
}

export default Crypto;

const APP_KEY = 暗号化キー;

暗号化キーは直接書いても良いですし、.envファイルに設定しても良いと思います。


Vue.jsのプラグイン登録

import Crypto from './plugins/encrypter';
Vue.use(Crypto);

暗号化

this.crypto.encrypt('暗号化したい文字列');

復号化

this.crypto.decrypt('this.crypto.encryptで暗号化された文字列');

関連記事

人気の投稿

最新の投稿

タグ

月別アーカイブ