Android Studio/Java - 具有小输入/输出大小的 RSA 加密
Posted
技术标签:
【中文标题】Android Studio/Java - 具有小输入/输出大小的 RSA 加密【英文标题】:Android Studio/ Java - RSA Encryption with small input/output size 【发布时间】:2017-09-03 20:35:13 【问题描述】:我被要求使用 RSA 加密在蓝牙节点之间发送数据,这是我研究任何形式的加密的第一周,所以我需要一些帮助。
似乎输出大小总是相对于模数的大小。 Mod 2048 和 1024 似乎很流行,它们分别具有 256 字节和 128 字节的输出大小。
我正在使用仅接受大小为 20(字节)的数据包的低功耗蓝牙(蓝牙智能)节点。
我的问题:如果我只能发送 20 个字节,加密数据有什么意义吗?我认为将 20 个字节的数据加密为 20 个字节是不合理的……这算不上什么加密。我什至不确定是否可以设置一个 160 的模数来加密它?如果您想知道,为什么模数是 160?这是因为如果 (2048 / 8 = 256 字节),则 (160 / 8 = 20 字节)。
新信息: 我无法发送多个数据包,因为该系统是网状系统。也就是说,每次我发送一个数据包时,节点都会断开与发送者的连接,然后将消息广播到空中的任何节点。我大约需要 4 秒才能发送第二个数据包。
到目前为止,我已经编写了一些测试代码,只是为了弄脏我的手并检查加密 20 字节的默认输出(最终输出为 256 字节)。
public class Encryption
// Possibly use files for saving keys
private static String PUBLIC_KEY_FILE = "Public.key";
private static String PRIVATE_KEY_FILE = "Private.key";
Key publicKey = null;
Key privateKey = null;
KeyPairGenerator kpg;
KeyPair kp;
Cipher cipher;
public Encryption()
try
kpg = KeyPairGenerator.getInstance("RSA");
kp = kpg.generateKeyPair();
publicKey = kp.getPublic();
privateKey = kp.getPrivate();
catch (Exception e)
Log.e("Encryption", "RSA KeyPair Error...");
e.printStackTrace();
// Encode
public byte[] encode(byte[] bytesToEncode)
byte[] encodedBytes = null;
try
// Basic Cipher (mode/padding excluded for now)
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
encodedBytes = cipher.doFinal(bytesToEncode);
catch (Exception e)
Log.e("Encryption", "RSA Encoding Error...");
e.printStackTrace();
return encodedBytes;
public byte[] decode(byte[] encodedBytes)
byte[] decodedBytes = null;
try
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
decodedBytes = cipher.doFinal(encodedBytes);
catch (Exception e)
Log.e("Encryption", "RSA Decoding Error...");
e.printStackTrace();
return decodedBytes;
正如您在我的全局变量中看到的那样,稍后我将不得不更改代码以在某些时候保存这些密钥,而不是每次都重新创建它们,因此我总是使用相同的密钥对。此外,我需要将公钥文件提供给编写节点固件的工程师,以便他可以解码我的加密。由于我严格使用字节,所以我不应该遇到字符集问题。
【问题讨论】:
"只接受大小为 20(bytes) 的数据包..." 所以发送多个数据包。您在这里似乎也没有问题。 @JamesKPolk 请查看我添加的信息。我也强调了这个问题。由于我使用的是网状系统,因此我无法流式传输数据或同时发送数据包。当向我的一个节点发送数据包时,该节点从接收到发送,这会终止连接。我需要大约 4 秒才能再次“看到”蓝牙节点。 160 位 RSA 提供的安全性如此之低,以至于打扰都毫无意义。 160 位椭圆曲线密码学要强大得多,但仍远低于当代标准。不幸的是,您的要求非常有限。 @JamesKPolk 谢谢。我想我只是在寻找第二种意见,因为我对密码学知之甚少。请发布答案,以便我接受并给予您适当的信任。 我建议您在 crypto.stackexchange.com 上提问,而不是发布答案。与其发布您的代码,不如简单地提及您的要求。他们那里有很多专家,其中一些人可能在网状网络/资源受限的密码学方面有经验。 【参考方案1】:您正在尝试重新发明***:
您应该只使用 RSA 对您将在设备之间共享的随机生成的密钥进行签名和加密,而不是交换任何其他类型的数据。
那么您应该使用这些具有对称算法的密钥来验证和加密设备之间的数据。
如今,标准 RSA 密钥长度约为 2048 位。
如今,标准的 AES 对称密钥长度约为 256 位。
但是密钥大小和块大小不一样:AES 块大小是 16 字节。这应该很适合您的小包。
更准确地说,由于您的数据大小可能不完全是 16 个字节,因此您应该使用分组密码算法(例如 CBC)或流密码算法(例如 GCM)来使用 AES 或其他对称算法。
最先进的 AES-256-GCM 算法将身份验证和加密集成在单个流密码中。由于您应该始终在尝试解密数据之前对其进行身份验证(大多数不遵守此规则的人都遇到了问题),因此仅使用 AES-256-CBC 之类的东西是个坏主意。
最后,请注意,您正在使用的蓝牙 LE 引入了 AES-CCM,以实现机密性、完整性和身份验证。愿您基于此功能进行交流以实现您的目标。
【讨论】:
谢谢,我明白你说的大部分内容。看起来我将不得不使用带有填充的块/流密码算法?有没有推荐的教程? 由于您使用 Java 进行编程,因此您应该真正考虑使用 BouncyCastle 而不是 Java 加密 API 的本机实现。也许你可以从这里开始:***.com/questions/885485/…以上是关于Android Studio/Java - 具有小输入/输出大小的 RSA 加密的主要内容,如果未能解决你的问题,请参考以下文章
android studio java.io.IOException:setDataSourse fail.
Android studio java.lang.UnsatisfiedLinkError
Android Studio Java JDK环境路径[重复]