加密算法以可发音的方式匿名字符串?

信息安全 哈希 隐私 匿名
2021-09-06 10:24:51

注意:我最初在 SO(链接)上发布了这个,但后来意识到 Security SE 更合适,因为存在关于 Crypto-PAn 的问题,这与这里类似

我有一个我想匿名的数据库查询日志文件——这些是从客户端获得的,然后在外部进行分析。客户希望将这些匿名化到足以保护识别信息的程度,但仍要留下足够的空间以进行有用的分析。

有些行可能包含 IP 地址(例如源 IP)——我相信我可以使用Crypto-PAn 之类的东西来匿名这些。我的理解是,这种匿名化是单射的 (1:1) 以及可重复的,但也是不可逆的。

同样,行也可能包含字段和值 - 例如{ "name.first": "John" }

对于这些值,我很高兴只使用直接的 MD5(或类似的内容)——我们看到它们是什么并不重要。

但是,对于数据库字段,我们希望以某种人类可读的格式保存它们。这是因为我们将围绕这些字段进行性能分析(例如,按字段分组查询等)

例如,name.first可能变成Tree.Blackboard.

约束是:

  • 每个输入单词都应该映射到一个哈希,反之亦然(我知道会有一些冲突,但希望它们足够罕见)。
  • 可重复 - 如果我们有多个日志文件,我们希望每次生成相同的哈希 - 这将允许我们跨日志文件进行比较。
  • 不可逆 - 理想情况下,不应该有一种简单的方法来反转哈希以获取原始字段名称。
  • 人类可读 - 哈希应该是人类可读/可发音的,但它们不一定需要是有效的英文单词(例如Flerti可以接受,037751d79d1ebfdd0664b2c66b8d66d1不是)

我和一位同事讨论过,我们认为的一种方式是:

  • 获取字段名称 - 并通过标准的单向哈希(例如 MD5)传递它。
  • 从生成的哈希中获取足够的低位位以映射到英语单词字典(例如 1,000,000 个有效单词)。使用这些位的整数等价物,并做一个 mod 来索引该字典中的一个单词。

这个想法是 - 单词是可读的,但也总是一致的(假设你的字典保持不变)。

如果某些人担心字典攻击(即字段名称“firstname”总是映射为“Blackboard”),那么该人可以拥有自己的特定密钥文件来对哈希进行加盐。这意味着来自他们的匿名日志文件将是可重复的(即“名字”可能总是映射到他们的“十亿”),但与使用其他密钥文件的其他人不同。

问题 1 - 是否已经有一种现有的加密算法(类似于 Crypto-PAn)可用于以某种可发音/可读的方式对字符串进行匿名化?

问题 2 - 如果没有,您是否看到上述简单方法中有任何明显的漏洞?

2个回答

您可以尝试音节哈希。

从一个基本的哈希算法开始来消化单个数据标识符;它并不一定是加密强度,我建议不要这样做。大多数实现都会产生一个完美的字节数组;少数会产生一个更大的基元或更大的基元数组,在这种情况下,您需要将它们拆分为字节。

然后,查找或创建映射到简单辅音值对(Ba、Be、Bi、Bo、Bu、Cha、Che、Chi、Cho、Chu、Da、De、Di、Do、Du 等)的可能字节值的查找)。音节的顺序及其到字节值的映射无关紧要;散列是操作的不可逆部分,而不是音节映射。请记住,您只会得到 256,如果您使用安全散列,则包含一些添加信息而不添加音节(连字符或元音将添加到前一个音节的元音以创建双元音或有向图)。

使用 FNV-1 或 Murmur 之类的基本 32 位校验和哈希,这将为您提供 2-4 音节范围内看似随机构造的单词,平均趋势较高(并且可识别的单音节单词的机会几乎不存在,尤其是如果前导零被视为与字节数组中的内联零或尾随零相同)。使用加密散列,您可能必须对字节进行 XOR 折叠,因为 SHA-1 之类的东西会给您 10 个音节的单词,这就是为什么我不建议使用加密散列的原因。

它可能听起来像一些替代现实日语,但您将能够发音生成的标识符。为了让它听起来更像英语,你可以从最常见的英语音节列表开始,比如这个但是,此列表将包括常见的音节,因为它们是词根的前缀或后缀,而您将在词中的随机位置注入它们。

你想达到什么目的?您是否希望对包含敏感数据的数据库进行匿名化处理,以便能够安全地将其提供给外部 QA 测试团队,而不会影响内容?在这种情况下,将个人和公司名称匿名化是不够的,因为其余数据也有足迹,可以向数据所有者得出结论。您还说每个数据都应该映射到哈希,反之亦然,但它不应该是可逆的。这是一个矛盾,不可能两者兼得。

关于算法,看看 PGP 如何创建指纹。它们是可发音的和散列的,由一系列英语单词组成。

虽然散列函数本身是不可逆的,但散列允许唯一标识属于该散列的记录。

有可用的 PGP 的开源克隆,因此您应该能够获得源代码。

您可以添加一个字段,而不是散列,您可以在该字段中填充由算法生成的随机字符串,例如:

void Main()
{
    MakeRandomString(4).Dump();
}


private string MakeRandomString(int n)  
{  
    var bits = new List<string>()  
    {  
            "na",  "bla",  "chee",  "dee",  "ay",              
            "tree", "th",  "goo",  "foo",              
            "ook",  "ta",  "bee",              
            "zoo",  "ai",  "kawee",  "jam",  "ya"            
    };  

    StringBuilder sb = new StringBuilder();  
    Random r = new Random();  
    for (int i = 0; i < n; i++)  
    {  
        sb.Append(bits[r.Next(bits.Count)]);  
    }  

    return sb.ToString();  
}  

这将创建随机的幻想词,例如:

cheekaweefoobla
yataaitree
deetreenana

这是我从这里获取的稍微更改的代码。对于导出,您可以使用该字段作为参考。它将能够映射原始行。您可以使用加密随机生成器改进上面的代码。