Encryption Decryption of salary slip and structure

Hi, I am trying to encrypt or decrypt all the information related to employee salary. But i am not able to do it for doctype ‘Salary Structure Earning’ and “Salary Structure Deduction” doctype. Please help.

@Manav, by default ERPNext or Frappe dont support data encryption, do you need use a third party library to do this work! Like python-cryptography

Just by curiosity, do you can explain what is the use case?

1 Like

What is the use case? Please share your code?

Cryptography.py

I have added this file for encrytion/decryptiuon of text string.

import frappe
def get_key():
# Encryption key is datetime of creation of DocType, DocType"
#import webnotes
#webnotes.conn.sql(“select creation from tabDocType where name=‘DocType’”)[0][0].strftime(‘%Y%m%d%H%M%s’)[:16]
return “1234567890123456”

def encrypt(data, encryption_key = None):
try:
if data:
if not encryption_key:
encryption_key = get_key()
return crypt(encryption_key, str(data)).encode(‘hex’)
return data
except:
return data

def decrypt(data, encryption_key = None):
try:
if data:
if not encryption_key:
encryption_key = get_key()
return crypt(encryption_key, str(data).decode(‘hex’))
return data
except:
return data

def crypt(key,data,iv=‘\00\00\00\00\00\00\00\00’,n=32):
def keygen(key,iv,n):
while True:
iv = xtea_encrypt(key,iv,n)
for k in iv:
yield ord(k)
xor = [ chr(x^y) for (x,y) in zip(map(ord,data),keygen(key,iv,n)) ]
return “”.join(xor)

def xtea_encrypt(key,block,n=32,endian=“!”):
import struct
v0,v1 = struct.unpack(endian+“2L”,block)
k = struct.unpack(endian+“4L”,key)
sum,delta,mask = 0L,0x9e3779b9L,0xffffffffL
for round in range(n):
v0 = (v0 + (((v1<<4 ^ v1>>5) + v1) ^ (sum + k[sum & 3]))) & mask
sum = (sum + delta) & mask
v1 = (v1 + (((v0<<4 ^ v0>>5) + v0) ^ (sum + k[sum>>11 & 3]))) & mask
return struct.pack(endian+“2L”,v0,v1)

def xtea_decrypt(key,block,n=32,endian=“!”):
import struct

v0,v1 = struct.unpack(endian+"2L",block)
k = struct.unpack(endian+"4L",key)
delta,mask = 0x9e3779b9L,0xffffffffL
sum = (delta * n) & mask
for round in range(n):
    v1 = (v1 - (((v0<<4 ^ v0>>5) + v0) ^ (sum + k[sum>>11 & 3]))) & mask
    sum = (sum - delta) & mask
    v0 = (v0 - (((v1<<4 ^ v1>>5) + v1) ^ (sum + k[sum & 3]))) & mask
return struct.pack(endian+"2L",v0,v1)

salary_structure.py

from frappe.utils.cryptography import encrypt,decrypt
def validate(self):
self.check_existing()
self.validate_amount()
self.validate_employee()
set_employee_name(self)
self.encrypt_money_info() # this will encryt the field values.
def encrypt_money_info(self): # this will encrypt the money info and store it to db.
self.total_earning=encrypt(self.total_earning)
self.net_pay=encrypt(self.net_pay)
self.total_deduction=encrypt(self.total_deduction)

@frappe.whitelist()
def get_money_information(param):
# This is used to display decrypted information to UI. This method will be called through AJAX
import json
json_acceptable_string = param.replace(“'”, “"”)
parameters = json.loads(json_acceptable_string)
data={}

if parameters:
    for key, value in parameters.iteritems():
        data[key]=decrypt(parameters.get(key,""))
return data

salary_structure.js
var getSalaryInfo=function(param,value){
data={};
data[“_total_earning”]=param.total_earning;
data[“_net_pay”]=param.net_pay;
data[“_total_deduction”]=param.total_deduction;
return data;
}

cur_frm.cscript.refresh = function(doc, dt, dn){
if((!doc.islocal) && (doc.is_active == ‘Yes’)){
cur_frm.add_custom_button(
(‘Make Salary Slip’),
cur_frm.cscript[‘Make Salary Slip’], frappe.boot.doctype_icons[“Salary Slip”]);
}
if (!doc.__islocal){
salary_info=getSalaryInfo(doc);
cur_frm.call({
method: “get_money_information”, // This method will decrypt the values and return the fields object to ui.
args: {param: salary_info},
callback:function(r1){
doc.total_earning=r1.message._total_earning;
doc.net_pay=r1.message._net_pay;
doc.total_deduction=r1.message._total_deduction;
refresh_many([“total_earning”,“net_pay”,“total_deduction”]);
}
});
}
}

The problem which i am facing is how to encrypt/decrypt child tables i.e salary structure earning and salary structure deduction.

@Manav why this complexity is required?

I need to encrypt the data in database for some specific fields of salary tables.

@Manav, this is crazy! You completely forgot that the database have datatypes!

How do you expect store a Numeric data encrypted in the database? The database never will allow you to do it!

Another thing, your encryptation Key, is very insecure, since it is part of the record it-self!

I have change it to varchar(255).

@Manav, just run a for in each entity, and encrypt the fields that do you need!

Thanks,

Yeah encryption has been done now but while showing decrypted value for earning_details and deduction_details “refresh_many” is not working.

if (!doc.__islocal){
salary_info=getSalaryInfo(doc);
cur_frm.call({
method: “get_money_information”,
args: {param: salary_info},
callback:function(r1){
doc.total_earning=r1.message._total_earning;
doc.net_pay=r1.message._net_pay;
doc.total_deduction=r1.message._total_deduction;
for(var i = 0; i < r1.message._deduction_details; i++){
doc.deduction_details[i][“d_modified_amt”]=r1.message._deduction_details[i][“d_modified_amt”];
}
for(var i = 0; i < r1.message._earning_details; i++){
doc.earning_details[i][“modified_value”]=r1.message._earning_details[i][“modified_value”];
}

            **refresh_many(["total_earning","net_pay","total_deduction","earning_details","deduction_details"]);** // **code not working for earning_details.**
        }
    });
}