Haszowanie PESELu
public class PH {
private static byte[] hash(String in, String key) throws Exception {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(key.getBytes());
return md.digest(in.getBytes());
}
private static String fillNumber(String s, int len) {
while (s.length() < len)
s = "0"+s;
return s;
}
private static String byte2String(byte[] b, int len) {
StringBuffer sb = new StringBuffer();
for (int i=0; i < Math.min(b.length, len); i++) {
int c = '0' + (b[i] & 0xff)%10;
sb.append((char)c);
}
return sb.toString();
}
public static void main(String[] args) throws Exception {
HashMap<String, String> map = new HashMap<String, String>();
int hc = 0;
for (int i=0; i < 100000; i++) {
String pesel = "721028" + fillNumber(i+"", 5);
String hash5 = byte2String( hash(pesel, "random123!"), 10);
if (map.get(hash5)!=null) {
System.err.println("Kolizja dla peselu "+pesel+" => "+hash5 + " => "+map.get(hash5));
hc++;
}
else
map.put(hash5, pesel);
}
System.err.println("Kolizji: "+hc);
}
}
Haszowanie PESELu ma być częściowe, czyli nie zmieniamy daty urodzenia, a tylko 5 ostatnich cyfr. Jeżeli ze standardowo zahaszowanego stringu z peselem wybierzemy poniżej 10 znaków (z 16) jako klucz, to mamy kolizje. Ponad 36000 na 100000 dla 5 znaków.
Workaround:
CREATE OR REPLACE
PROCEDURE HASH_OSOBY AS
type ROWID_TAB is table of rowid index by binary_integer;
collisions rowid_tab;
collisions_cnt number := 0;
passes number := 0;
key varchar2(4000) := 'klucz1';
err varchar2(4000) := '';
BEGIN
dbms_output.disable;
for rec in (select rowid from monitor.os) loop
begin
update monitor.os set pesel = haszujpesel(pesel, key) where rowid=rec.rowid;
exception when others then
collisions_cnt := collisions_cnt+1;
collisions(collisions_cnt) := rec.rowid;
err := SQLERRM;
insert into log_h(T,LOG) values(sysdate(),err);
end;
end loop;
insert into log_h(T,LOG) values(sysdate(), 'Pass '||passes||', number of collisions: '||collisions_cnt);
while collisions.count > 0 loop
key := key||key;
for i in collisions.first..collisions.last loop
begin
update monitor.os set pesel = haszujpesel(pesel, key) where rowid=collisions(i);
collisions.delete(i);
exception when others then
err := SQLERRM;
insert into log_h(T,LOG) values(sysdate(),err);
end;
end loop;
passes := passes + 1;
collisions_cnt := collisions.count;
insert into log_h(T,LOG) values(sysdate(), 'Pass '||passes||', number of collisions: '||collisions_cnt);
end loop;
END HASH_OSOBY;
Kończąc niniejsze rozważania należy powiedzieć, że w ramach ochrony danych osobowych dane testowe powinny zawierać w pełni zahaszowane PESELe, a o spójność PESELi z datami urodzenia po zahaszowaniu powinien zadbać autor bazy.
0 komentarze:
Prześlij komentarz