【问题标题】:swift sodium Decrypt using Private Key使用私钥快速钠解密
【发布时间】:2017-09-19 14:05:04
【问题描述】:

我在客户端使用 Swift Sodium,因为我的服务器使用 libsodium 加密数据,然后通过 API 与我共享。

现在我有一个现有的私钥和一个字符串格式的公钥。我现在想在 iOS 上使用 Swift 解密加密数据。

如何使用我拥有的公钥和私钥生成 Sodium 密钥对?

另外,理想情况下,我应该只使用私钥来解密数据。那么我该如何只使用私钥作为字符串来做到这一点。

我的解密代码如下所示 -

func decryptData(dataString: String) -> String? {
    let sodium = Sodium()
    let privateKey = sodium?.utils.hex2bin("MY_SECRET_KEY")

    let publicKey = sodium?.utils.hex2bin("MY_PUBLIC_KEY")

    let message = dataString.data(using: .utf8)!

    if let decrypted = sodium?.box.open(anonymousCipherText: message, recipientPublicKey: publicKey!, recipientSecretKey: privateKey!){
        // authenticator is valid, decrypted contains the original message
        return String(data: decrypted, encoding: String.Encoding.utf8) as String!
    }
    return nil
}

在上面的代码中,我解密的字符串总是空的。

服务器正在使用以下函数加密数据 -

protected function crypt($response)
{
   $message = new HiddenString($response);

   $repository = \App::make(EncryptionKeysRepository::class);
   $enc = $repository->findOneBy(['device' => 'android']);
   $dir = $enc->getDevice();
   $publicKey = $enc->getPublicKey();
   $storage = storage_path();

   if(!file_exists($storage."/{$dir}/")) {
       mkdir($storage."/{$dir}/");
   }

   // save key pair to key store
   $pubFilename = \tempnam($storage."/{$dir}/", 'pub_key');
   file_put_contents($pubFilename, $publicKey);

   $public = KeyFactory::loadEncryptionPublicKey($pubFilename);
   unlink($pubFilename);
   rmdir($storage."/{$dir}/");
   $message = Crypto::seal($message, $public);

   return $message;
}

在服务器端解密逻辑

protected function deCrypt($response)
{
   $repository = \App::make(EncryptionKeysRepository::class);
   $enc = $repository->findOneBy(['device' => 'android']);
   $dir = $enc->getDevice();
   $publicKey = $enc->getSecretKey();
   $storage = storage_path();

   if(!file_exists($storage."/{$dir}/")) {
       mkdir($storage."/{$dir}/");
   }

   // save key pair to key store
   $secFilename = \tempnam($storage."/{$dir}/", 'sec_key');
   file_put_contents($secFilename, $publicKey);

   $secret = KeyFactory::loadEncryptionSecretKey($secFilename);
   unlink($secFilename);
   rmdir($storage."/{$dir}/");
   $res = Crypto::unseal($response, $secret);

   $message = $res->getString();

   return response()->json(compact('message'));
}

【问题讨论】:

  • 您的dataString 是什么格式的?也许是base64或其他格式,你必须在解密之前对其进行解码?
  • @algrid 它只是一个加密的字符串。上面没有编码,所以不需要解码。

标签: php ios swift libsodium sodium


【解决方案1】:

所以,在服务器端,您显然在使用 PHP,并带有一个名为 Halite 的库。

我对 Halite 不是很熟悉,但是看它的代码,Crypto::seal() 使用密封的盒子,所以Box::open(anonymousCipherText: Data, recipientPublicKey: PublicKey, recipientSecretKey: SecretKey) -> Data? 是在 Swift 中解密它的正确方法。

不过,Halite 似乎也将结果编码为 BASE64 字符串(urlsafe 变体)。

因此,您需要先对此进行解码。或者,这将更有效,不要对密文进行编码。除非您必须大声朗读它们,否则密钥可能也不需要编码。

【讨论】:

  • 我尝试对其进行解码,但解码后的数据始终为零,因此我假设它不是 base64 编码的。我用过这个 - let decodedData = Data(base64Encoded: dataString)
  • 确保使用正确的 BASE64 变体。如上所述,默认情况下,Halite 似乎使用 BASE64 的 URLsafe 变体。
  • 检查了所有变种弗兰克。我不认为它的 base64encoded 是诚实的,因为一切都为零
  • 还在服务器端添加了解密逻辑,它工作正常并且能够解密相同的字符串
  • 它已编码,否则 JSON 编码也可能会失败。检查解码后的密文长度是否等于原始消息长度加48字节。密钥对是如何在设备上生成的?还是您在任何地方都使用相同的密钥对?在这种情况下,你最好使用对称加密。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-31
相关资源
最近更新 更多