Code:
- H/TITLE CIPHER - Module to encrypt and decrypt data
- Hnomain
- *****************************************************************
- * RPG IV module CIPHER *
- * Author: Matt Haas *
- * Description: Common functions to encrypt and decrypt data. *
- * *
- * This module can handle up to 65,520 bytes of *
- * data. This is 15 bytes less than 64k. This size *
- * was used because it is the maximun character *
- * field size that falls on a 16 byte boundry. *
- * *
- * AES ciphers will operate of 16 byte blocks of *
- * data. Padding will be added to ensure that a *
- * full block of data is encrypted. What this *
- * means is the return data size will be a multiple *
- * of 16 bytes (5 bytes in will be 16 bytes out, *
- * 17 bytes in will be 32 bytes out, etc...) *
- * *
- *Mark Date MDY User ID Rel Call # Description *
- *---- -------- -------- ---- -------- ------------------------ *
- *F993 05/25/05 TPCHAASM Initial create. *
- * *
- *****************************************************************
-
- /COPY JDECPY,#CIPHER
-
- DGenAESSalt PR 16A
-
- Dcipher PR extproc('_CIPHER')
- D receiver *
- D control 96A OPTIONS(*VARSIZE)
- D source *
-
- DAES_Controls DS
- D FunctionID 2A
- D DataLen 5U 0
- D Operation 1A
- D Mode 1A
- D BlockLength 3U 0
- D MAClength 3U 0
- D InitVector 32A
- D Reserved 7A
- D KeyOption 1A
- D KeySchedulePtr *
- D Key 32A
-
- DKeySchedule S 1088A
- DOP_ENCRYPT C const(x'00')
- DOP_DECRYPT C const(x'01')
- DOP_MAC C const(x'02')
- DMODE_ECB C const(x'00')
- DMODE_CBC C const(x'01')
- DKEYOPT_SCHEDULE C const(x'00')
- DKEYOPT_16BYTE C const(x'10')
- DKEYOPT_24BYTE C const(x'18')
- DKEYOPT_32BYTE C const(x'20')
- DFUNCID_PRN C const(x'0008')
- DFUNCID_AES C const(x'0015')
- DBLOCK_LENGTH C const(16)
-
- *//////////////////////////////////////////////////////////////*
- * (Aes128bitEncrypt) Encrypt data using 128-bit AES *
- *//////////////////////////////////////////////////////////////*
- PAes128bitEncrypt...
- P B export
- *--------------------------------------------------------------*
- DAes128bitEncrypt...
- D PI 65520A varying
- D Password 16A value
- D ClearText 65504A varying value
-
- Dbuff_in S 16A
- Dbuff_out S 16A
- DNumChunks S 10I 0
- Dctr S 10I 0
- DStartPos S 10I 0
- DCipherText S 65520A varying
- Dp_recv S *
- DP_src S *
- Dsalt S 16A
- DlastBlock S 16A varying
-
- /free
-
- salt = GenAESSalt();
-
- // Encrypt using 128-bit AES, 16 byte chunks
- AES_Controls = *ALLx'00';
- FunctionID = FUNCID_AES;
- DataLen = BLOCK_LENGTH;
- Operation = OP_ENCRYPT;
- Mode = MODE_CBC;
- BlockLength = BLOCK_LENGTH;
- KeyOption = KEYOPT_16BYTE;
- KeySchedulePtr = %addr(KeySchedule);
- Key = Password;
- InitVector = salt;
-
- p_recv = %addr(buff_out);
- p_src = %addr(buff_in);
-
- // Pad the clear text
- NumChunks = %len(ClearText) / BLOCK_LENGTH;
-
- // If the length of the clear text is an exact
- // multiple of the block size, we need to subtract
- // 1 from NumChunks to get the last BLOCK_SIZE
- // bytes of the data.
- If %len(ClearText) = (NumChunks * BLOCK_LENGTH);
- NumChunks = NumChunks - 1;
- EndIf;
- lastBlock = %subst(ClearText: (NumChunks * BLOCK_LENGTH) + 1);
-
- // Replace the last block of clear text with the padded value
- ClearText = %subst(ClearText: 1 : (NumChunks * BLOCK_LENGTH))
- + AddPKCS5Padding(lastBlock);
-
- // Determine how many 16 byte blocks need encrypted
- NumChunks = %len(ClearText) / BLOCK_LENGTH;
- If (NumChunks * BLOCK_LENGTH) < %len(ClearText);
- NumChunks = NumChunks + 1;
- EndIf;
-
- StartPos = 1;
- %len(CipherText) = 0;
-
- // Encrypt the passed in data
- For ctr = 1 to NumChunks;
- // If we're doing the last part of the clear text,
- // we need to make sure it's padded out to 16 bytes
- // with the padding character passed in.
- If ctr = NumChunks;
- If (StartPos + BLOCK_LENGTH) > %len(ClearText);
- buff_in = %subst(ClearText: StartPos);
- Else;
- buff_in = %subst(ClearText: StartPos: BLOCK_LENGTH);
- EndIf;
- Else;
- buff_in = %subst(ClearText: StartPos: BLOCK_LENGTH);
- EndIf;
- cipher( p_recv: AES_Controls: p_src);
- CipherText = CipherText + buff_out;
- StartPos = StartPos + BLOCK_LENGTH;
- KeyOption = KEYOPT_SCHEDULE;
- EndFor;
-
- // Add the salt to the CipherText
- CipherText = salt + CipherText;
-
- return CipherText;
- /end-free
-
- PAes128bitEncrypt...
- P E
-
-
- *//////////////////////////////////////////////////////////////*
- * (Aes128bitDecrypt) Decrypt data using 128-bit AES *
- *//////////////////////////////////////////////////////////////*
- PAes128bitDecrypt...
- P B export
- *--------------------------------------------------------------*
- DAes128bitDecrypt...
- D PI 65504A varying
- D Password 16A value
- D CipherText 65520A varying value
-
- Dbuff_in S 16A
- Dbuff_out S 16A
- DNumChunks S 10I 0
- Dctr S 10I 0
- DStartPos S 10I 0
- DCipherWork S 65520A varying
- DClearText S 65520A varying
- Dp_recv S *
- DP_src S *
- DCipherTextLen S 10I 0
-
- /free
- // Decrypt using 128-bit AES, 16 byte chunks
- AES_Controls = *ALLx'00';
- FunctionID = FUNCID_AES;
- DataLen = BLOCK_LENGTH;
- Operation = OP_DECRYPT;
- Mode = MODE_CBC;
- BlockLength = BLOCK_LENGTH;
- KeyOption = KEYOPT_16BYTE;
- KeySchedulePtr = %addr(KeySchedule);
- Key = Password;
-
- // First 16 bytes contains the salt
- InitVector = %subst(CipherText: 1: 16);
-
- // Remove the salt from CipherText
- CipherWork = %subst(CipherText: 17);
-
- p_recv = %addr(buff_out);
- p_src = %addr(buff_in);
-
- // Determine how many 16 byte blocks need decrypted
- NumChunks = %len(CipherWork) / BLOCK_LENGTH;
- If (NumChunks * BLOCK_LENGTH) < %len(CipherWork);
- NumChunks = NumChunks + 1;
- EndIf;
-
- StartPos = 1;
- %len(ClearText) = 0;
-
- For ctr = 1 to NumChunks;
- buff_in = %subst(CipherWork: StartPos: BLOCK_LENGTH);
- cipher( p_recv: AES_Controls: p_src);
- If (ctr = NumChunks);
- buff_out = RemovePKCS5Padding(buff_out);
- EndIf;
- ClearText = ClearText + buff_out;
- StartPos = StartPos + BLOCK_LENGTH;
- KeyOption = KEYOPT_SCHEDULE;
- EndFor;
-
- return %trimr(ClearText);
- /end-free
-
- PAes128bitDecrypt...
- P E
-
- *//////////////////////////////////////////////////////////////*
- * (RemovePKCS5Padding) Remove padding characters using the *
- * PKCS5 method. *
- *//////////////////////////////////////////////////////////////*
- PRemovePKCS5Padding...
- P B export
- *--------------------------------------------------------------*
- DRemovePKCS5Padding...
- D PI 16A varying
- D paddedBlock 16A
-
- DpadCheck C const(x'0102030405060708090A0B0C0D0E-
- D 0F10')
-
- DpadChar S 1A
- DnumPadChars S 10I 0
- DunPadded S 16A varying
-
- /free
- // padChar will give us the hex representation of
- // how many characters to strip off the decyphered
- // text. For example, if padChar = x'10', we need to
- // remove all 16 characters from the decoded text
- // since 10 is the hex value of 16
-
- padChar= %subst(paddedBlock: BLOCK_LENGTH: 1);
- numPadChars = %scan(padChar: padCheck);
-
- Select;
- When numPadChars = 16;
- %len(unPadded) = 0;
- When numPadChars > 0 and numPadChars < 16;
- unPadded = %subst(paddedBlock: 1 :BLOCK_LENGTH - numPadChars);
- Other;
- unPadded = paddedBlock;
- EndSl;
-
- return unPadded;
- /end-free
-
- PRemovePKCS5Padding...
- P E
-
- *//////////////////////////////////////////////////////////////*
- * (AddPKCS5Padding) Adds padding characters using the PKCS5 *
- * method. *
- *//////////////////////////////////////////////////////////////*
- PAddPKCS5Padding B export
- *--------------------------------------------------------------*
- DAddPKCS5Padding PI 32A varying
- D inBlock 16A varying
-
- DpadChars C const(x'0102030405060708090A0B0C0D0E-
- D 0F10')
-
- DpadChar S 1A
- Dpadded S 32A varying
- DpadCharsNeeded S 10I 0
- Dctr S 10I 0
-
- /free
- padded = inBlock;
-
- // Determine how many padding bytes to add. For full blocks,
- // add 16 bytes of padding.
- padCharsNeeded = 16 - %len(inBlock);
- If padCharsNeeded = 0;
- padCharsNeeded = 16;
- EndIf;
-
- padChar = %subst(padChars: padCharsNeeded: 1);
-
- For ctr = 1 to padCharsNeeded;
- padded = padded + padChar;
- EndFor;
-
- return padded;
- /end-free
-
- PAddPKCS5Padding E
-
- *//////////////////////////////////////////////////////////////*
- * (GenAESSalt) Generate a 16 byte salt for use with AES. *
- *//////////////////////////////////////////////////////////////*
- PGenAESSalt B
- *--------------------------------------------------------------*
- DGenAESSalt PI 16A
-
- DPRN_Controls DS
- D FunctionID 2A
- D SeedRequest 1A
- D Reserved1 3A
- D SeedLength 5U 0
- D PRNRequest 1A
- D PRNParity 1A
- D Reserved2 4A
- D NumberOfPRNs 5U 0
- D Reserverd3 16A
-
- DNO_SEED C const(x'00')
- DADD_SEED C const(x'01')
- DGEN_REAL_PRN C const(x'00')
- DGEN_TEST_PRN C const(x'01')
- DNO_PARITY C const(x'00')
- DODD_PARITY C const(x'01')
- DEVEN_PARITY C const(x'02')
-
- Dp_recv S *
- DP_src S *
- Dbuff_in S 16A
- Dbuff_out S 16A
-
- /free
- p_recv = %addr(buff_out);
- p_src = %addr(buff_in);
-
- //
- // Setup CIPHER for a secure random number
- //
-
- PRN_Controls = *ALLx'00';
- FunctionID = FUNCID_PRN;
- PRNRequest = GEN_REAL_PRN;
- // NumberOfPRNs is the number of bytes to return.
- NumberOfPRNs = 16;
- PRNParity = NO_PARITY;
-
-
- //
- // Generate a secure random number
- //
-
- cipher(p_recv: PRN_Controls: p_src);
-
- return buff_out;
-
- /end-free
- PGenAESSalt E
|
|