SAS中的数据屏蔽:在字符级别加扰敏感观察

时间:2013-05-16 08:28:56

标签: encryption sas masking scramble data-masking

我正在使用SAS中的客户数据处理敏感的客户识别信息。挑战是以这样的方式掩盖该领域,使其保持数字/字母/字母数字。我找到了一种在SAS(BXOR,BOR,BAND)中使用Bitwise函数的方法,但输出中充满了SAS无法处理/排序/合并等特殊字符。

我还想过根据一把钥匙来扰乱这个领域,但是还没有看到它。以下是挑战:

1)它必须是基于密钥的 2)是可逆的。 3)屏蔽/加扰字段必须是数字/字母/字母数字,因此可以在SAS中使用。 4)要屏蔽的字段既有字母也有数字,但长度不一,有数百万个观察点。

关于如何实现这种掩蔽/加扰的任何提示都将大有裨益:(

2 个答案:

答案 0 :(得分:2)

这是一个简单的基于密钥的解决方案。我在这里介绍了数据步骤解决方案,然后将介绍一个FCMP版本。我将所有内容保留在48到127之间(数字,字母和常用字符,例如@><等等);这不是字母数字,但我无法想象在这种情况下为什么会这么重要。您可以使用相同的方法将其进一步减少为真正的字母数字,但它会使密钥更糟(仅62个值)并且使用起来很笨(因为您有3个不连续的范围)。

data construct_key;
length keystr $1500;
do _t = 1 to 1500;
  _rannum = ceil(ranuni(7)*80);
  *if _rannum=12 then _rannum=-15;
  substr(keystr,_t,1)=byte(47+_rannum);

end;
call symput('keystr',keystr);
run;
%put %bquote(&keystr);



data encrypted;
set sashelp.class;
retain key "&keystr";
length name_encrypt $30;
do _t = 1 to length(name);
  substr(name_encrypt,_t,1) = byte(mod(rank(substr(name,_t,1)) + rank(substr(key,1,1))-94,80)+47);
  key = substr(key,2);
end;
keep name:;
run;

data unencrypted;
set encrypted;
retain key "&keystr";
length name_unenc $30;
do _t = 1 to length(name_encrypt);
  substr(name_unenc,_t,1) = byte(
      mod(80+rank(substr(name_encrypt,_t,1)) - rank(substr(key,1,1)),80)
+47);
  key = substr(key,2);
end;
run;

在此解决方案中,存在中等级别的加密 - 具有80个可能值的密钥不足以阻止真正复杂的黑客,但对于大多数目的而言足够强大。您需要将密钥本身或种子传递给密钥算法才能解密;如果您多次使用此选项,请确保每次都选择一个新种子(而不是与数据相关的内容)。如果你使用零(或非定义整数)种子,你每次都会有效地保证一个新密钥,但你必须传递密钥本身而不是种子,这可能会带来一些数据安全问题(显然,密钥本身可以是由恶意用户获得,并且必须存储在与数据不同的位置)。通过种子传递密钥可能更好,因为你可以通过电话口头或通过某种预先安排的种子列表传递密码。

我不确定我一般会推荐这种方法;一种优越的方法可能是使用优越的加密方法(例如PGP)简单地加密整个SAS数据集。您的确切解决方案可能会有所不同,但如果您有一些客户信息对于您的流程的大多数步骤而言实际上并不是必需的,那么您最好将这些信息与其他(非敏感)数据分开,并且只能合并当它需要时。

例如,我有一个流程,我为客户提供样本进行医疗保健调查。我从数据集中选择有效记录,该数据集除了数字唯一标识符外没有客户信息;一旦我将样本缩小到有效记录,然后我附加来自单独数据集的客户信息并创建邮件文件(存储在加密目录中)。这样可以尽可能长时间地保持数据不敏感。它并不完美 - 独特的数字标识符仍然意味着有一个回限,即使它不是任何人在项目之外知道的任何事情 - 但它会尽可能长时间保持安全。

以下是FCMP版本:

%let keylength=5;
%let seed=15;

proc fcmp outlib=work.funcs.test;
subroutine encrypt(value $,key $);
  length key $&keylength.;
  outargs value,key;
  do _t = 1 to lengthc(value);
    substr(value,_t,1) = byte(mod(rank(substr(value,_t,1)) + rank(substr(key,1,1))-62,96)+31);
    key = substr(key,2)||substr(key,1,1);
  end;
endsub;

subroutine unencrypt(value $,key $);
  length key $&keylength.;
  outargs value,key;
  do _t = 1 to lengthc(value);
    substr(value,_t,1) = byte(mod(96+rank(substr(value,_t,1)) - rank(substr(key,1,1)),96)+31);
    key = substr(key,2)||substr(key,1,1);
  end;
endsub;

subroutine gen_key(seed,keystr $);
  outargs keystr;
  length keystr $&keylength.;
  do _t = 1 to &keylength.;
    _rannum = ceil(ranuni(seed)*80);    
    substr(keystr,_t,1)=byte(47+_rannum);
  end;
endsub;
quit;

options cmplib=work.funcs;



data encrypted;
set sashelp.class;
length key $&keylength.;
retain key ' '; *the missing is to avoid the uninitialized variable warning;
if _n_ = 1 then call gen_key(&seed,key);
call encrypt(name,key);
drop key;
run;

data unencrypted;
set encrypted;
length key $&keylength.;
retain key ' ';
if _n_ = 1 then call gen_key(&seed,key);
call unencrypt(name,key);
run;

这有点强大;它允许字符从32到127而不是48,这意味着它成功处理空间。 (Tab仍然无法正确解码 - 它将是'k'。)你传递种子来调用gen_key,然后它将该键用于剩余的进程。

毋庸置疑,这并不能保证能够满足您的目的和/或成为安全的解决方案,如果您有大量的安全需求,您应该咨询安全专家。本帖子不保证出于任何目的,海报不承担由于使用而产生的任何和所有责任。

答案 1 :(得分:1)

SAS在他们的网站上有一篇关于如何加密特定变量的文章。希望这对你有帮助。

link