Pythonic解决加密敏捷性问题,避免违反Liskov替换原则

时间:2011-10-27 15:36:10

标签: python oop encryption

我需要在python中围绕对称密码(AES,DES等)以各种操作模式编写一组包装器,允许crypto agility。具体来说,调用包装器的代码不需要知道实际保护数据的内容,因此可以动态更改它

基本上应该包含以下内容(无论是对象上的方法,单独的函数还是其他内容)

foo = MagicalEncryptor()
foo.ciphertext = foo.encrypt(data)
key = foo.key 
bar = MagicalEncryptor()
bar.key = key 
data = bar.decrypt(ciphertext)

问题在于,根据使用的模式,生成的密文会有所不同。对于CBC或(MODE_GCM,IV,密文,mac),GCM模式可以是(MODE_CBC,IV,密文)。

这显然违反了Liskov substitution principle,因为它使得参数解密协变。如果调用者持有碰巧用于GCM模式的通用magicalEncryptor接口的实例,则它无法将其作为ECB模式的实例。

对此有什么好的pythonic解决方案? (或者答案根本就不在乎?)对于我特别需要做的事情,它应该在2.7和3.0中都有效,但我对两者的解决方案都很感兴趣。

此外,密钥必须具有短表示作为比特流(最多可能是128或256位)。这适用于混合加密方案,例如,可以发送(RSA_ENC(PublicKey,symetric_key_as_message)|| AES(symetric_key_as_message,actual_message)。

3 个答案:

答案 0 :(得分:1)

跟随Kirk,但在最后一分钟剥离,让多态密钥负责选择正确的解密器:

foo = MagicalEncryptor()
foo.ciphertext = foo.encrypt(data)
key = foo.key 

bar = key.decryptor()
data = bar.decrypt(ciphertext)

它可以创建适当的解密器并自行传递。或者其他:密钥和解密器创建之间的协议是私有的。

我甚至可以重新安排这样的事情:

key = createMagicalKey()

foo = key.encryptor()
ciphertext = foo.encrypt(data)

bar = key.decryptor()
data = bar.decrypt(ciphertext)

当然,这只是一个简单的步骤:

key = createMagicalKey()

ciphertext = key.encrypt(data)

data = key.decrypt(ciphertext)

答案 1 :(得分:0)

方法一:强力输入加密数据:

class GCMData(object):
    def __init__(self, data): self.data = data

    def __str__(self): return self.data
    __repr__ = __str__


class MagicalGCMEncryptor(object):
    def encrypt(self, data):
        return GCMData(self._encrypt(data))

    def decrypt(self, dataobj):
        if not isinstance(dataobj, GCMData):
            raise ValueError('Only decrypts GCM data')

方法二:反转流量控制。不要创建加密数据的类。制作存储加密数据的数据对象:

class GCMEncryptedData(object):
    def __init__(self, data):
        self.data = [... do something with data]

    def __str__(self): return self.data
    __repr__ = __str__

    def decrypt(self):
        return [... do something with self.data]

答案 2 :(得分:0)

“这显然违反了Liskov替换原则,因为它使得参数解密协变。如果调用者持有碰巧用于GCM模式的泛型magicalEncryptor接口的实例,则它无法将其作为ECB模式的实例。“

也不应该。加密不能是与模式无关的黑盒子。是的,您可以在不更改大量更高级别逻辑的情况下将TDES与AES-256交换,但对于更改加密模式则不然。将模式视为协议,将算法视为引擎。协议很复杂,因为它需要自己的特殊错误报告,故障机制,初始化过程,相关数据,状态信息等。相比之下,交换算法引擎很容易。

例如,在使用GCM时,您需要注意不要加密过多的邮件,并且要更快地旋转密钥以保持mac的加密强度。无论是TDES-GCM还是AES-256-GCM都是如此。这意味着您应该跟踪已加密的消息数量 - 即使这是一个大概的估计,例如“使用模式Y时每隔X天重新生成密钥”(尽管您真的关心处理的数据量。)

您对欧洲央行没有这些担忧(在实际层面上),但您对信息泄漏有一套完全不同的(更困难的)担忧。

CBC模式有其自身的使用缺陷,特别是如果您还使用CBC-MAC。根据所使用的身份验证方法,您需要注意在MAC失败时报告错误消息 - 在某些情况下,MAC的失败会导致密钥的破坏(例如会话密钥),但在其他情况下会失败MAC应该只导致重置协议运行(保持您的身份验证密钥集)。或者也许可以重播消息 - 这取决于您构建协议的方式以及您正在使用的算法。

如果对存储的数据使用调整加密模式,则关心数据驻留在磁盘上的位置,如果要覆盖块,则将重新使用相同的调整键和位置值。但是,如果您正在加密频道,则永远不会重复使用具有相同会话密钥的消息计数器。适合于加密数据就地的加密模式与适合于加密信道的加密模式没有重叠。它们不能相互交换。

所有这些都违反了Liskov替换原则,除非您尝试实现可以​​专注于所有可想到的数据保护协议的通用“安全”对象。

此外,你永远 *永远*在两种不同的模式或两种不同的算法引擎中使用相同的密钥。

那么为什么要以一种允许密钥对象的实例专门用于多个算法实现的方式设计代码呢?现在,您的安全团队将重新审视您的代码,并确保此通用性不会为攻击者打开任何漏洞,让您的应用程序以错误的方式使用它来滥用密钥。您将需要返回并确保在实例化密钥时,完全指定在密钥的构造函数中使用它的模式和算法,这可以追溯到密钥长度的问题。任何后续尝试在使用与实例化的不同算法或模式的密钥中使用密钥都应导致严重错误。

但在这种情况下,如果用户或应用程序需要在每次底层系统采用新算法时都需要创建新密钥和/或重新生成现有数据,那么“算法敏捷性”是什么意思?

相关问题