wiki:security/electronic_signatures

Version 4 (modified by Sam Habiel, 11 years ago) ( diff )

--

Use of Electronic Signatures to Secure VISTA Data

Statement of Problem

The crux of the issue is the ability to store data on patients and be able to detect if the patient data has been changed intentionally or unintentionally since it was entered. Compounding this issue is the need for different people at different points in time to be able to see the data that was entered. This means that the data creator's token cannot be used as a way to secure the data against future modification. The system has to also support document retraction and reassignment, which override the data creator's authority on the document.

An example is in order: how do you know if the text of a TIU note is the same as what the original user entered?

Implementation in VISTA

Various parts of VISTA accomplish this using the encryption and decryption functionality. The encryption algorithm used is a stream cipher (I am not exactly sure which one). For TIU documents, the cipher algorithm uses the document's checksum of document contents as one of the vectors in the algorithm to encrypt the signer's name and title. If the document is modified outside of TIU, the user will see gibberish for these two fields.

For example, this is a typical signature:

/es/ DOCTOR MCDUCK, MD
ENT PHYSICIAN
Signed: 02/27/2013 09:34

If the document is changed outside of TIU, it may look like this (this example isn't real as I do not have access to the algorithm):

/es/ lks&*(*% *(*&@#$*&
A#@^*(ssDASDF
Signed: 02/27/2013 09:34

Other VISTA packages, notably Radiology, implement the same functionality, using other vectors for encryption.

Use in VISTA outside of the VA

The FOIA process removes sensitive security related algorithms from VISTA. As a result, those using VISTA outside of the Veteran's Administration have had to supplement this. I have surveyed all the external VISTAs and here is what I found on how they were replaced:

ItemWorldVistAOpenVistavxVista
Access/Verify HashReversible HashNoneMD5 Hash
Electronic Signature HashNoneRestore VA RoutineMD5 Hash
Encryption/DecryptionNoneRestore VA RoutineBlowfish symmetric block cipher

As you can see from this table, both OpenVista and WorldVistA have done badly (it's not known whether the OpenVista version is even legal) while vxVista has done the best.

A solution to hashing and encryption on GT.M

I wrote this routine to replace XUSHSHP:

UJOSHSHP ; VEN/SMH - Encrypt Data a la XUSHSHP ;2013-02-27  9:44 AM
 ;;1.0;JORDAN SPECIFIC MODIFICATIONS;
 ;
HASH ; HASH
 Q:'$D(X)  Q:'$L(X)
 ; Input: X from Symbol Table. X can be any length
 ; Output: X hashed, as 20 characters
 ;
 ; Use sha512 with user stuff as salt
 ; Should use PBKDF2, bcrypt, or scrypt; but not available in openssl CLI.
 S X=$$UP^XLFSTR(X) ; Uppercase X; per original VA code.
 N SALTED S SALTED=$P(^VA(200,DUZ,1),U,7)_X_DUZ ; Salt X with User Creation Date and DUZ.
 N CALL S CALL="openssl dgst -sha512" ; SHA512 OS call
 N DEVICE S DEVICE="hashPipe"
 N OUTPUT
 N OLDIO S OLDIO=$IO
 OPEN DEVICE:(shell="/bin/sh":comm=CALL)::"PIPE"
 USE DEVICE WRITE SALTED,/EOF READ OUTPUT:1 U OLDIO CLOSE DEVICE
 S X=$E(OUTPUT,$L(OUTPUT)-19,$L(OUTPUT)) ; X is the return variable; only 20 characters long
 QUIT
 ;
EN ; ENCRYPT
 Q:'$D(X)!('$D(X1))!('$D(X2))  Q:'$L(X)
 ; Expect X, X1, X2
 ; X is the string to encrypt. X1 and X2 are salts/password
 ; X1 can be the DUZ
 ; X2 can be the checksum of the text to encrypt
 ; Output: X, the encrypted string. Length is the same the input.
 ; Maximum supported length is maximum global node length.
 ; Encrypting word processing fields is not supported.
 ;
 ; AES- Cipher Block Chaining with Base 64 encoding with password w no salt.
 N CALL S CALL="openssl enc -a -aes-256-cbc -nosalt -pass pass:"_X1_X2
 ; N CALL S CALL="openssl enc -a -des-ede3-cbc -nosalt -pass pass:"_X1_X2
 ; N CALL S CALL="openssl enc -bf-cbc -nosalt -pass pass:"_X1_X2
 ; N CALL S CALL="openssl enc -a -rc4 -nosalt -pass pass:"_X1_X2
 N DEVICE S DEVICE="encryptionPipe"
 N OLDIO S OLDIO=$IO
 OPEN DEVICE:(shell="/bin/sh":comm=CALL)::"PIPE"
 USE DEVICE
 WRITE X,/EOF ; Write the string to encrypt
 N I,OUTPUT ; I = counter. OUTPUT = encyrpted tems
 FOR I=1:1 READ OUTPUT(I) Q:$ZEOF  ; Read it into Output Array
 U OLDIO
 CLOSE DEVICE
 ; Next two lines: concatentate the array into the root node
 S OUTPUT="" 
 F I=1:1 Q:'$D(OUTPUT(I))  S OUTPUT=OUTPUT_OUTPUT(I) K OUTPUT(I)
 ; X is the output from the API
 S X=OUTPUT
 QUIT
 ;
DE ; DECRYPT
 Q:'$D(X)!('$D(X1))!('$D(X2))  Q:'$L(X)
 ; Expect X, X1, X2
 ; X is the string to encrypt. X1 and X2 are salts/password
 ; X1 can be the DUZ
 ; X2 can be the checksum of the text to encrypt
 ; Output: X, the decrypted string. Length is the same the input.
 ; Maximum supported length is maximum global node length.
 ; Encrypting word processing fields is not supported.
 N CALL S CALL="openssl enc -d -a -aes-256-cbc -nosalt -pass pass:"_X1_X2
 ; N CALL S CALL="openssl enc -a -d -rc4 -nosalt -pass pass:"_X1_X2
 N DEVICE S DEVICE="decryptionPipe"
 N OLDIO S OLDIO=$IO
 OPEN DEVICE:(shell="/bin/sh":comm=CALL)::"PIPE"
 USE DEVICE
 F  W $E(X,1,64),! S X=$E(X,65,1024*1024*1024) Q:X=""  ; Write Input base64 style
 WRITE /EOF
 N OUTPUT R OUTPUT:1 ; Read Output of decryption back.
 U OLDIO
 CLOSE DEVICE
 S X=OUTPUT ; X is output
 QUIT
 ;
RUNTESTS S IO=$P S DIQUIET=1 D DT^DICRW D:$L($T(EN^XTMUNIT)) EN^XTMUNIT($T(+0),1) QUIT
THASH ; @TEST - Test Hashing
 N DUZ
 S DUZ=1 N X S X="HELLO WORLD" D HASH
 N RESULT1 S RESULT1=X
 S DUZ=1 N X S X="HELLO WORLD" D HASH
 N RESULT2 S RESULT2=X
 D CHKEQ^XTMUNIT(RESULT1,RESULT2,"Hash results are not equal")
 ;
 S DUZ=1 N X S X="HELLO WORLD" D HASH
 N RESULT1 S RESULT1=X
 S DUZ=2 N X S X="HELLO WORLD" D HASH
 N RESULT2 S RESULT2=X
 D CHKTF^XTMUNIT(RESULT1'=RESULT2,"Hash results are not supposed to be equal")
 ;
 S DUZ=1
 N X S X="Hello World" D HASH
 N RESULT1 S RESULT1=X
 N X S X="HELLO WORLD" D HASH
 N RESULT2 S RESULT2=X
 D CHKEQ^XTMUNIT(RESULT1,RESULT2,"Hash results of different cases aren't equal")
 QUIT
 ;
THASH2 ; @TEST - Test Hashing using main calling routine XUSHSHP
 N DUZ
 S DUZ=1 N X S X="HELLO WORLD" D HASH^XUSHSHP
 N RESULT1 S RESULT1=X
 S DUZ=1 N X S X="HELLO WORLD" D HASH^XUSHSHP
 N RESULT2 S RESULT2=X
 D CHKEQ^XTMUNIT(RESULT1,RESULT2,"Hash results are not equal")
 ;
 S DUZ=1 N X S X="HELLO WORLD" D HASH^XUSHSHP
 N RESULT1 S RESULT1=X
 S DUZ=2 N X S X="HELLO WORLD" D HASH^XUSHSHP
 N RESULT2 S RESULT2=X
 D CHKTF^XTMUNIT(RESULT1'=RESULT2,"Hash results are not supposed to be equal")
 ;
 S DUZ=1
 N X S X="Hello World" D HASH^XUSHSHP
 N RESULT1 S RESULT1=X
 N X S X="HELLO WORLD" D HASH^XUSHSHP
 N RESULT2 S RESULT2=X
 D CHKEQ^XTMUNIT(RESULT1,RESULT2,"Hash results of different cases aren't equal")
 QUIT
 ;
TENC ; @TEST - Test Encryption
 N VALUE S VALUE="Mary has a little lamb"
 S X=VALUE,X1=1,X2=234234234
 D EN,DE ; encrypt, decrypt X
 D CHKEQ^XTMUNIT(VALUE,X,"Encryption and decryption didn't happen properly")
 ;
 N VALUE2 S VALUE2="Mary has a little lamb"
 S X=VALUE2,X1=88,X2=234234234
 D EN ; encrypt
 N ENCSTR1 S ENCSTR1=X
 S X=VALUE2,X1=1,X2=234234234 ; Different X1
 D EN ; encrypt
 N ENCSTR2 S ENCSTR2=X
 D CHKTF^XTMUNIT(ENCSTR1'=ENCSTR2,"Encrypted strings with different passwords are not supposed to be equal")
 QUIT
 ;
TENC2 ; @TEST - Test Encryption by calling XUSHSHP
 N VALUE S VALUE="Mary has a little lamb"
 S X=VALUE,X1=1,X2=234234234
 D EN^XUSHSHP,DE^XUSHSHP ; encrypt, decrypt X
 D CHKEQ^XTMUNIT(VALUE,X,"Encryption and decryption didn't happen properly")
 ;
 N VALUE2 S VALUE2="Mary has a little lamb"
 S X=VALUE2,X1=88,X2=234234234
 D EN^XUSHSHP ; encrypt
 N ENCSTR1 S ENCSTR1=X
 S X=VALUE2,X1=1,X2=234234234 ; Different X1
 D EN^XUSHSHP ; encrypt
 N ENCSTR2 S ENCSTR2=X
 D CHKTF^XTMUNIT(ENCSTR1'=ENCSTR2,"Encrypted strings with different passwords are not supposed to be equal")
 QUIT
LENGTH ; @TEST - Test Lengths
 N X,X1,X2,I
 S (X1,X2)=982734987234
 W !
 F I=1:1:60 K X S $P(X,"A",I)="A" W $L(X) D EN W ?30,$L(X),!
 QUIT

Attachments (1)

Download all attachments as: .zip

Note: See TracWiki for help on using the wiki.