ios Swift“加密”使用RSA私钥和安全框架的字符串

qhhrdooz  于 2022-11-19  发布在  iOS
关注(0)|答案(1)|浏览(209)

我正在做一个静态库,它接受一个输入字符串,用私钥加密它,然后返回它。(因为客户端请求在移动的端使用私钥。)
我正在修改这篇文章和this post中的代码以使用私钥,但是结果字符串总是返回nil。
测试密钥:

let privateTestingKey = "-----BEGIN RSA PRIVATE KEY-----MIICXwIBAAKBgQDPJfl0gC95kB3sS0SOfXW45UooiYjT3ZeHRDn/eG+So09x7cXLVbRILxxXfaU+9b5Yw2wETMvuzhP8C5Qd5PQy5lkH5LjcqJjDTvOBuBxNOSY4rmlqdy/skqM4FHjTGdwI2nZiVkjqOFXM+XZ94Ar+pszJifbSPElR1pO4NfT76QIDAQABAoGBAJjtoRdoFyR4yA6NlsRXTRS+ehwpRVGcc2TScrrvL/ejB2DFuFOgJyNvXE4fHWK4y9j+FP2rsJbRnyFhbu0O/VRNPa5Llnejea+5ov/3wxFqiae7pn6bjmiW/xdy0ycLWo90wLX9QqYjKBHomnh15FIajmSuRaUlBaL6DiZt010tAkEA0zLTPiH35meyXim7I7+mMmAN68zGu3cYpqq8i/xlHvXjWrBDV5saxRDsm97ktFqiRpvIoV3n0ZoT+3xjKhGINwJBAPsXM9hWdmWUXmaaAnXZDmKbNltRSZaaz4BktGRUJM0grt7kMndfBgd2JENNzYTfLpOWMIfHXpW9T4pVCjg5TN8CQQDGZf91ZbmYUx+HP5KSUY4R0pQhR/wEzSt2HfwDUPW5cOnEHsMUQBuUtoJfJrMYDfBVfjCqDiogh6pv2/jX4yJfAkEAqwsvQhwEI0Zi2DnpmyX1aq6Y5LQHERT8bVYsnHvFZgbxmNySlEai8MpGAaMqcW0naVpSTOw/PnnriSxM/efquQJBAM/3eRqzBHp/v3bRM+npSgEOaeOmtNiz+oNrJ09mUToyDTkuFOg7J9ojNkeviR4xqs9Hoos8lP3ho1uVcE3/tRQ=-----END RSA PRIVATE KEY-----"

RSA加密的代码:

import Foundation
import Security

public class MPEncryption {
  var publicKey: SecKey!
  
  public init(publicKeyString: String) throws {
    self.publicKey = try makePublicKey(from: publicKeyString)
  }
  
  private func makePublicKey(from keyString: String) throws -> SecKey {
    let pubKeyData = Data(base64Encoded: sanitize(key: keyString))!
    
    let query: [String: Any] = [
      kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
      kSecAttrKeyClass as String: kSecAttrKeyClassPrivate,
      kSecAttrKeySizeInBits as String: 1024
    ]
    
    var unmanagedError: Unmanaged<CFError>?
    
    guard let pubKeyRef = SecKeyCreateWithData(pubKeyData as CFData, query as CFDictionary, &unmanagedError) else {
      throw unmanagedError!.takeRetainedValue() as Error
    }
    
    return pubKeyRef
  }
  
  public func encrypt(value: String) throws -> String {
    let valueData = value.data(using: .utf8)!
    
    let bufferSize = SecKeyGetBlockSize(publicKey) - 11
    let buffers = makeBuffers(fromData: valueData, bufferSize: bufferSize)
    
    var encryptedData = Data()
    
    for buffer in buffers {
      var encryptionError: Unmanaged<CFError>?
      
      guard let encryptedBuffer = SecKeyCreateEncryptedData(publicKey, .rsaEncryptionPKCS1, buffer as CFData, &encryptionError) as Data? else {
        throw encryptionError!.takeRetainedValue() as Error
      }
      
      encryptedData.append(encryptedBuffer)
    }
    
    return encryptedData.base64EncodedString()
  }
  
  private func makeBuffers(fromData data: Data, bufferSize: Int) -> [Data] {
    guard data.count > bufferSize else {
      return [data]
    }
    
    var buffers: [Data] = []
    
    for i in 0..<bufferSize {
      let start = i * bufferSize
      
      let lengthOffset = start + bufferSize
      let length = lengthOffset < data.count ? bufferSize : data.count - start
      
      let bufferRange = Range<Data.Index>(NSMakeRange(start, length))!
      buffers.append(data.subdata(in: bufferRange))
    }
    
    return buffers
  }
  
  private func sanitize(key: String) -> String {
    let headerRange = key.range(of: "-----BEGIN RSA PRIVATE KEY-----")
    let footerRange = key.range(of: "-----END RSA PRIVATE KEY-----")
    
    var sanitizedKey = key
    
    if let headerRange = headerRange, let footerRange = footerRange {
      let keyRange = Range<String.Index>(uncheckedBounds: (lower: headerRange.upperBound, upper: footerRange.lowerBound))
      sanitizedKey = String(key[keyRange])
    }
    
    return sanitizedKey
      .trimmingCharacters(in: .whitespacesAndNewlines)
      .components(separatedBy: "\n")
      .joined()
  }
}

我找不到问题所在,欢迎提出任何建议。

4ktjp1zp

4ktjp1zp1#

调用encrypt()方法时,计算机上显示以下错误消息:

encrypt:RSA:PKCS1: algorithm not supported by the key <SecKeyRef algorithm id: 1, key type: RSAPrivateKey, ...>

这并不奇怪,因为代码试图使用私钥(在代码中标记为公钥,这是误导性的!)进行加密。但是,私钥仅用于签名,而公钥用于加密。

  • 使用私钥加密 * 并不是由库一致实现的。一些库从私钥中提取公钥并使用公钥加密,一些库使用私钥创建签名,而其他库根本不支持此功能(如此处的库)。

在我看来,您的需求最有可能是创建签名。加密和签名在技术上是相似的,但不同之处在于加密使用公钥进行模幂运算,而签名使用私钥。此外,填充变量也不同。但目的是 * 完全 * 不同的。加密是关于机密性的,而签名是关于验证真实性的。
因此,你可以尝试用签名代替加密。为此,只需稍微修改代码(不过,变量名迟早也会被修改):

guard let encryptedBuffer = SecKeyCreateSignature(publicKey, .rsaSignatureDigestPKCS1v15Raw, buffer as CFData, &encryptionError) as Data? else {
  throw encryptionError!.takeRetainedValue() as Error
}

encryptedData现在包含签名(并且publicKey表示私钥)。
请注意,对于rsaSignatureDigestPKCS1v15Raw,消息是 * 直接 * 签名的,即没有散列或考虑摘要ID。由于没有指定摘要ID,因此这可能是正确的变体。
但是,请注意,消息长度是有限的(类似于加密)。符合标准的是散列和摘要ID的考虑,这是通过例如SHA-256的rsaSignatureMessagePKCS1v15SHA256实现的。

相关问题