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;