DBA Data[Home] [Help]

PACKAGE BODY: APPS.FND_CRYPTO

Source


1 PACKAGE body fnd_crypto AS
2 /* $Header: AFSOCTKB.pls 120.3 2006/07/08 00:50:31 jnurthen noship $ */
3 
4   --- ENCRYPT AND DECRYPT ---
5 
6   PADRAW CONSTANT raw(36) := hextoraw('010202030303040404040505050505060606' || '060606070707070707070808080808080808');
7 
8   -- Bad Type
9   BadType EXCEPTION;
10 
11   -- Pad Padding (decryption failed)
12   BadPadding EXCEPTION;
13   PRAGMA EXCEPTION_INIT(BadPadding, -12656);
14 
15   --- HASH and MAC ---
16 
17   IPAD raw(64) := '36363636363636363636363636363636' ||
18                   '36363636363636363636363636363636' ||
19                   '36363636363636363636363636363636' ||
20                   '36363636363636363636363636363636';
21   OPAD raw(64) := '5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C' ||
22                   '5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C' ||
23                   '5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C' ||
24                   '5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C';
25 
26   --- RANDOM ---
27 
28   NORMLZ CONSTANT number := power(2,31);
29   SHIFTL CONSTANT number := power(2,32);
30   ENCNML CONSTANT number := power(2,63);
31   ENCNMM CONSTANT number := power(2,64);
32   XTONUM CONSTANT varchar2(32) := 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
33 
34   --- ENCODE AND DECODE ---
35 
36   TYPE CharMapType IS TABLE OF BINARY_INTEGER INDEX BY BINARY_INTEGER;
37 
38   NUMTOX CONSTANT varchar2(32)  := 'FM0XXXXXXXXXXXXXXX';
39   BASE64 CONSTANT number        := power(2,6);
40 
41   ENC_B64 CONSTANT varchar2(66) := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
42   ENC_URL CONSTANT varchar2(66) := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-.';
43 
44   function make_map_to(mapsrc in varchar2) return CharMapType;
45   function make_map_from(mapsrc in varchar2) return CharMapType;
46 
47   map_to_b64   CONSTANT CharMapType := make_map_to(ENC_B64);
48   map_to_url   CONSTANT CharMapType := make_map_to(ENC_URL);
49   map_from_b64 CONSTANT CharMapType := make_map_from(ENC_B64);
50   map_from_url CONSTANT CharMapType := make_map_from(ENC_URL);
51 
52   --- END DECLARATIONS ---
53 
54   function numtohex(n in number, siz in pls_integer default 128)
55     return varchar2
56   is
57     ret varchar2(100);
58   begin
59     if (siz = 128) then
60       ret := to_char(trunc(n/power(2,64)), NUMTOX) ||
61              to_char(mod  (n,power(2,64)), NUMTOX);
62     elsif (siz < 65) then
63       ret := to_char(mod  (n,power(2,64)), rpad('FM0X',2+2*trunc((siz+7)/8),'X'));
64     else
65       ret := to_char(trunc(n/power(2,64)), rpad('FM0X',2+2*trunc((siz-57)/8),'X')) ||
66              to_char(mod  (n,power(2,64)), NUMTOX);
67     end if;
68     return rtrim(ltrim(ret));
69   end;
70 
71   function NumToTwosComp(num in number)
72     return varchar2
73   is
74     ret raw(100);
75   begin
76     if (num < 0) then
77       return utl_raw.bit_complement(NumToTwosComp(-(num+1)));
78     end if;
79     if (num < ENCNML) then
80       return to_char(mod  (num,power(2,64)), NUMTOX);
81     end if;
82     return NumToTwosComp(trunc(num/ENCNMM)) || to_char(mod(num,ENCNMM),NUMTOX);
83   end NumToTwosComp;
84 
85   function TwosCompToNum(r raw)
86     return varchar2
87   is
88     n number;
89   begin
90     if (to_number(utl_raw.substr(r,1,1),'XX') >= 128) then
91       return -TwosCompToNum(utl_raw.bit_complement(r))-1;
92     end if;
93     if (utl_raw.length(r) <= 16) then
94       return to_number(r, XTONUM);
95     end if;
96     return TwosCompToNum(utl_raw.substr(r,1,utl_raw.length(r)-16))*power(2,128)+
97            to_number(utl_raw.substr(r,-16), XTONUM);
98   end TwosCompToNum;
99 
100     ---------------------- ENCRYPT AND DECRYPT ------------------------
101 
102   function pkcs5pad(s raw) return raw
103   is
104     pad number;
105   begin
106     pad := 8 - MOD(utl_raw.length(s),8);
107     return utl_raw.concat(s, utl_raw.substr(PADRAW, pad*(pad-1)/2+1,pad));
108   end pkcs5pad;
109 
110   function des3e(s in raw,
111                  k in raw,
112                  i in raw,
113                  pd in varchar2) return raw is
114     t RAW(32767);
115   begin
116     if (upper(substr(pd,1,1)) = 'Y') then
117       t := pkcs5pad(s);
118     else
119       t := s;
120     end if;
121     t := utl_raw.bit_xor(t, '0123456789ABCDEF');
122     if (i is not null) then
123       t := utl_raw.bit_xor(t, utl_raw.substr(i,1,8));
124     end if;
125     t := SYS.dbms_obfuscation_toolkit.DES3Encrypt
126            (input=>t, key=>k,
127 which=>SYS.dbms_obfuscation_toolkit.ThreeKeyMode);
128     return t;
129   end des3e;
130 
131   FUNCTION Encrypt (plaintext   IN RAW,
132                     crypto_type IN PLS_INTEGER,
133                     key         IN RAW,
134                     iv          IN RAW)
135     RETURN RAW is
136     l_encrypted raw(32767);
137   begin
138     if crypto_type = DES3_CBC_PKCS5
139     then
140       l_encrypted :=  des3e(s => plaintext,
141                             k => key,
142                             i => iv,
143                             pd => 'Y');
144     else
145       raise BadType;
146     end if;
147     return l_encrypted;
148   end Encrypt;
149 
150   function pkcs5unpad(s raw) return raw
151   is
152     pad number;
153   begin
154     pad := TO_NUMBER(rawtohex(utl_raw.substr(s, -1)), 'XX');
155     if (pad < 1 or pad > 8) then raise BadPadding; end if;
156 
157     if utl_raw.compare(utl_raw.substr(PADRAW, pad*(pad-1)/2+1, pad),
158                        utl_raw.substr(s, -pad)) <> 0 then
159       raise BadPadding;
160     end if;
161 
162     return utl_raw.substr(s, 1, utl_raw.length(s) - pad);
163   end pkcs5unpad;
164 
165   function des3d(s in raw,
166                  k in raw,
167                  i in raw,
168                  pd in varchar2)
169            return raw is
170     t RAW(32767);
171   begin
172     t := SYS.dbms_obfuscation_toolkit.DES3Decrypt
173            (input=>s, key=>k,
174 which=>SYS.dbms_obfuscation_toolkit.ThreeKeyMode);
175     t := utl_raw.bit_xor(t, '0123456789ABCDEF');
176     if (i is not null) then
177       t := utl_raw.bit_xor(t, utl_raw.substr(i,1,8));
178     end if;
179     if (upper(substr(pd,1,1)) = 'Y') then
180       t := pkcs5unpad(t);
181     end if;
182     return t;
183   end des3d;
184 
185   FUNCTION Decrypt (cryptext    IN RAW,
186                     crypto_type IN PLS_INTEGER,
187                     key         IN RAW,
188                     iv          IN RAW)
189     RETURN RAW is
190     l_decrypted raw(32767);
191   begin
192     if crypto_type = DES3_CBC_PKCS5
193     then
194       l_decrypted :=  des3d(s => cryptext,
195                             k => key,
196                             i => iv,
197                             pd => 'Y');
198     else
199       raise BadType;
200     end if;
201 
202     return l_decrypted;
203   end;
204 
205 
206   FUNCTION EncryptNum(num       IN NUMBER,
207                       key       IN RAW,
208                       iv        IN RAW         DEFAULT NULL)
209     RETURN VARCHAR2
210   IS
211   BEGIN
212     return encode(des3e(NumToTwosComp(num), key, iv, 'N'), ENCODE_URL);
213   END EncryptNum;
214 
215 
216   FUNCTION DecryptNum(cryptext  IN VARCHAR2,
217                       key       IN RAW,
218                       iv        IN RAW         DEFAULT NULL)
219     RETURN NUMBER
220   IS
221   BEGIN
222     return TwosCompToNum(des3d(decode(cryptext,ENCODE_URL),key,iv,'N'));
223   END DecryptNum;
224 
225 
226   ---------------------- HASH and MAC ------------------------
227 
228     FUNCTION Hash (source    IN RAW,
229                    hash_type IN PLS_INTEGER)
230       RETURN RAW is
231     begin
232       return SYS.dbms_obfuscation_toolkit.md5(input => source);
233     end;
234 
235     function kmd5_alg(src raw, key raw) return raw
236     is
237       ipk raw(64);
238       opk raw(64);
239       hsh raw(16);
240     begin
241       if (utl_raw.length(key) > 64) then
242         ipk := SYS.dbms_obfuscation_toolkit.md5(input => key);
243       else
244         ipk := key;
245       end if;
246       if (utl_raw.length(ipk) < 64) then
247         ipk := utl_raw.concat(ipk, rpad('0',128-2*utl_raw.length(ipk), '0'));
248       end if;
249       opk := utl_raw.bit_xor(ipk, OPAD);
250       ipk := utl_raw.bit_xor(ipk, IPAD);
251 
252       hsh := SYS.dbms_obfuscation_toolkit.md5(input => utl_raw.concat(ipk, src));
253       hsh := SYS.dbms_obfuscation_toolkit.md5(input => utl_raw.concat(opk, hsh));
254       return hsh;
255     end kmd5_alg;
256 
257     FUNCTION Mac (source   IN RAW,
258                   mac_type IN PLS_INTEGER,
259                   key      IN RAW)
260       RETURN RAW
261     is
262       tmp raw(16);
263     begin
264       if mac_type = HMAC_MD5
265       then
266         tmp := kmd5_alg(source, key);
267       elsif mac_type = HMAC_CRC
268       then
269         null; -- to be added
270       else
271         tmp := kmd5_alg(source, key);
272       end if;
273       return tmp;
274     end;
275 
276   ---------------------- RANDOM ------------------------
277 
278   FUNCTION RandomBytes(number_bytes IN POSITIVE)
279     RETURN RAW is
280     ret raw(32767);
281     tmp raw(2000);
282     len number := number_bytes;
283   begin
284     while (len <> 0) loop
285       if (len < 2000) then
286         tmp := FND_RANDOM_NUMBER.GET_RANDOM_BYTES(len);
287       else
288         tmp := FND_RANDOM_NUMBER.GET_RANDOM_BYTES(2000);
289       end if;
290       ret := utl_raw.concat(ret, tmp);
291       len := len - utl_raw.length(tmp);
292     end loop;
293     return ret;
294   end RandomBytes;
295 
296 
297   FUNCTION RandomNumber
298     RETURN NUMBER is
299   begin
300     return to_number(rawtohex(RandomBytes(16)), XTONUM);
301   end RandomNumber;
302 
303   FUNCTION SmallRandomNumber
304     RETURN NUMBER is
305     l_number number;
306   begin
307 
308     loop
309       l_number := floor(to_number(rawtohex(RandomBytes(4)), XTONUM)/2);
310       exit when l_number > 0 and l_number < 2147483647;
311     end loop;
312 
313     return l_number;
314   end SmallRandomNumber;
315 
316 
317   ---------------------- ENCODE AND DECODE ------------------------
318 
319   function encodeunit(unit in raw, len in pls_integer, mp in CharMapType)
320   return varchar2
321   is
322     na number      := to_number(rawtohex(unit),'XXXXXXXXXXXXXXXXXXXXXXXX');
323     nb number      := 0;
324     ln pls_integer := len;
325   begin
326     ln := mod(len, 3);
327     if (ln = 0) then
328       ln := 4*len/3;
329     elsif (ln = 1) then
330       nb := 257 * mp(64);
331       na := na * 16;
332       ln := (4*len + 2)/3;
333     else
334       nb := mp(64);
335       na := na * 4;
336       ln := (4*len + 1)/3;
337     end if;
338 
339     while (ln > 0) loop
340       nb := 256 * nb + mp(mod(na, BASE64));
341       na := trunc(na / BASE64);
342       ln := ln - 1;
343     end loop;
344 
345     return utl_raw.cast_to_varchar2(utl_raw.reverse(numtohex(nb, 8*4*trunc((len+2)/3))));
346   end encodeunit;
347 
348   function encodedrop(unit in raw, len in pls_integer, mp in CharMapType)
349   return varchar2
350   is
351     na number      := to_number(rawtohex(unit),'XXXXXXXXXXXXXXXXXXXXXXXX');
352     nb number      := 0;
353     ln pls_integer := len;
354   begin
355     while (ln > 0) loop
356       nb := 256 * nb + mp(mod(na, BASE64));
357       na := trunc(na / 256);
358       ln := ln - 1;
359     end loop;
360 
361     return utl_raw.cast_to_varchar2(utl_raw.reverse(numtohex(nb, 8*len)));
362   end encodedrop;
363 
364   function make_map_to(mapsrc in varchar2) return CharMapType
365   is
366     tmp CharMapType;
367     val raw(256):= utl_raw.cast_to_raw(mapsrc);
368   begin
369     for j in 1..utl_raw.length(val) LOOP
370       tmp(j-1) := to_number(utl_raw.substr(val, j, 1),'XX');
371     end LOOP;
372     return tmp;
373   end make_map_to;
374 
375   function make_map_from(mapsrc in varchar2) return CharMapType
376   is
377     tmp CharMapType;
378     val raw(256):= utl_raw.cast_to_raw(mapsrc);
379   begin
380     for j in 1..utl_raw.length(val) LOOP
381       tmp(to_number(utl_raw.substr(val, j, 1),'XX')) := j - 1;
382     end LOOP;
383     return tmp;
384   end make_map_from;
385 
386   function get_map(m in pls_integer, drp in out NOCOPY boolean) return CharMapType
387   is
388   begin
389     drp := false;
390     if    (m =  ENCODE_B64) then              return map_to_b64;
391     elsif (m =  ENCODE_URL) then              return map_to_url;
392     elsif (m =  ENCODE_ORC) then drp := true; return map_to_url;
393     elsif (m = -ENCODE_B64) then              return map_from_b64;
394     elsif (m = -ENCODE_URL) then              return map_from_url;
395     elsif (m = -ENCODE_ORC) then drp := true; return map_from_url;
396     end if;
397   end get_map;
398 
399   FUNCTION Encode (source   IN RAW,
400                    fmt_type IN PLS_INTEGER)
401     RETURN VARCHAR2 is
402     cur number := 1;
403     len number := utl_raw.length(source) + 1;
404     nxt number := len - cur;
405     ret varchar2(32767);
406     drp boolean;
407     mp CharMapType := get_map(fmt_type, drp);
408   begin
409     while (nxt > 0) loop
410       if (nxt > 12) then nxt := 12; end if;
411       if (not drp) then
412         ret := ret || encodeunit(utl_raw.substr(source, cur, nxt), nxt, mp);
413       else
414         ret := ret || encodedrop(utl_raw.substr(source, cur, nxt), nxt, mp);
415       end if;
416       cur := cur + nxt;
417       nxt := len - cur;
418     end loop;
419     return ret;
420   end Encode;
421 
422   function decodeunit(unit in varchar2, mp in CharMapType)
423   return raw
424   is
425     na number      := to_number(utl_raw.reverse(utl_raw.cast_to_raw(unit)),'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
426     nb number      := 0;
427     nc number;
428     ln pls_integer := 0;
429   begin
430     while (na > 0) loop
431       nc := mp(mod(na, 256));
432       if (nc = 64) then
433         na := 0;
434       else
435         ln := ln + 6;
436         nb := BASE64 * nb + nc;
437       end if;
438       na := trunc(na / 256);
439     end loop;
440 
441     nc := mod(ln, 8);
442     if (nc > 0) then
443       ln := ln - nc;
444       nb := nb / power(2,nc);
445     end if;
446 
447     return numtohex(nb, ln);
448   end decodeunit;
449 
450   function decodedrop(unit in varchar2, mp in CharMapType)
451   return raw
452   is
453     na number      := to_number(utl_raw.reverse(utl_raw.cast_to_raw(unit)),'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
454     nb number      := 0;
455     ln pls_integer := 0;
456   begin
457     while (na > 0) loop
458       nb := 256 * nb + mp(mod(na, 256));
459       na := trunc(na / 256);
460       ln := ln + 8;
461     end loop;
462 
463     return numtohex(nb, ln);
464   end decodedrop;
465 
466   FUNCTION Decode (source   IN VARCHAR2,
467                    fmt_type IN PLS_INTEGER)
471     nxt number := len - cur;
468     RETURN RAW is
469     cur number := 1;
470     len number := length(source) + 1;
472     ret raw(32767);
473     drp boolean;
474     mp CharMapType := get_map(-fmt_type, drp);
475   begin
476     while (nxt > 0) loop
477       if (nxt > 16) then nxt := 16; end if;
478       if (not drp) then
479         ret := ret || decodeunit(substr(source, cur, nxt), mp);
480       else
481         ret := ret || decodedrop(substr(source, cur, nxt), mp);
482       end if;
483       cur := cur + nxt;
484       nxt := len - cur;
485     end loop;
486     return ret;
487   end Decode;
488 
489   function RandomString(len  IN INTEGER,
490                         msk  IN VARCHAR2 default FND_CRYPTO_CONSTANTS.ALPHANUMERIC_UPPER_MASK,
491                         sublen IN INTEGER default 0,
492                         sublen_msk IN VARCHAR2 default FND_CRYPTO_CONSTANTS.ALPHABETIC_UPPER_MASK)
493            return VARCHAR2  IS
494 
495 
496     r_char varchar2(4000);
497     mask VARCHAR2(4000);
498     mask_length NUMBER;
499 	sublenmask_length NUMBER;
500     out_length NUMBER;
501 
502   BEGIN
503 
504 
505     IF sublen > len THEN
506       RAISE VALUE_ERROR;
507     END IF;
508 
509     IF (len > 1000) THEN
510       RAISE VALUE_ERROR;
511     ELSE
512       out_length := len-sublen;
513     END IF;
514 
515     IF (msk is null) or (sublen_msk is null and sublen > 0) then
516       RAISE VALUE_ERROR;
517     END IF;
518 
519     IF sublen > 0 THEN
520       sublenmask_length := length(sublen_msk);
521     END IF;
522     mask_length := length(msk);
523 
524     FOR i in 1..sublen LOOP
525       r_char := r_char || substr(sublen_msk,mod(fnd_crypto.randomnumber,sublenmask_length)+1,1);
526     END LOOP;
527 
528 
529     FOR i IN 1..out_length LOOP
530       r_char := r_char || substr(msk,mod(fnd_crypto.randomnumber,mask_length)+1,1);
531     END LOOP;
532     RETURN r_char;
533   END RandomString;
534 
535 END fnd_crypto;