【问题标题】:Obtain public key from private SecKeyRef从私有 SecKeyRef 获取公钥
【发布时间】:2014-08-19 16:44:21
【问题描述】:

鉴于使用来自 RSA 私钥的 SecItemImport 加载的 SecKeyRef 有没有办法仅为公钥组件获取或创建 SecKeyRef?在 OpenSSL 中,这可以通过将模数和公共指数复制到新结构来完成,但 SecKeyRef 是不透明的,我一直无法找到执行此操作的函数。

【问题讨论】:

    标签: c macos cryptography security.framework


    【解决方案1】:

    老问题,但因为我今天正在和它斗争,所以我找到了一种方法。假设您有用 Java (X509 证书公钥)创建的 base64 编码的公共 RSA 密钥(它不是证书,不是 der、pem...),您可以通过这种方式创建 SecKeyRef

    - (NSData *)stripPublicKeyHeader2:(NSData *)keyBits {
      // Skip ASN.1 public key header
      if (keyBits == nil) {
        return nil;
      }
    
      unsigned int len = [keyBits length];
      if (!len) {
        return nil;
      }
    
      unsigned char *c_key = (unsigned char *)[keyBits bytes];
      unsigned int  idx    = 0;
    
      if (c_key[idx++] != 0x30) {
        return nil;
      }
    
      if (c_key[idx] > 0x80) {
        idx += c_key[idx] - 0x80 + 1;
      }
      else {
        idx++;
      }
    
      if (idx >= len) {
        return nil;
      }
    
      if (c_key[idx] != 0x30) {
        return nil;
      }
    
      idx += 15;
    
      if (idx >= len - 2) {
        return nil;
      }
    
      if (c_key[idx++] != 0x03) {
        return nil;
      }
    
      if (c_key[idx] > 0x80) {
        idx += c_key[idx] - 0x80 + 1;
      }
      else {
        idx++;
      }
    
      if (idx >= len) {
        return nil;
      }
    
      if (c_key[idx++] != 0x00) {
        return nil;
      }
    
      if (idx >= len) {
        return nil;
      }
    
      // Now make a new NSData from this buffer
      return([NSData dataWithBytes:&c_key[idx] length:len - idx]);
    }
    
    - (SecKeyRef)publicKey:(NSData *)d_key withTag:(NSString *)tag
    {
      NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]];
    
      NSDictionary *saveDict = @{
                                 (__bridge id) kSecClass : (__bridge id) kSecClassKey,
                                 (__bridge id) kSecAttrKeyType : (__bridge id) kSecAttrKeyTypeRSA,
                                 (__bridge id) kSecAttrApplicationTag : d_tag,
                                 (__bridge id) kSecAttrKeyClass : (__bridge id) kSecAttrKeyClassPublic,
                                 (__bridge id) kSecValueData : d_key
                                 };
    
      OSStatus secStatus = SecItemAdd((__bridge CFDictionaryRef)saveDict, NULL );
      if (secStatus == errSecDuplicateItem ) {
        SecItemDelete((__bridge CFDictionaryRef)saveDict);
        secStatus = SecItemAdd((__bridge CFDictionaryRef)saveDict, NULL );
      }
    
      if ( secStatus != noErr ) {
        return NULL;
      }
    
      NSDictionary *queryDict = @{
                                  (__bridge id) kSecClass : (__bridge id) kSecClassKey,
                                  (__bridge id) kSecAttrKeyType : (__bridge id) kSecAttrKeyTypeRSA,
                                  (__bridge id) kSecAttrApplicationTag : tag,
                                  (__bridge id) kSecAttrKeyClass : (__bridge id)kSecAttrKeyClassPublic,
                                  (__bridge id) kSecReturnRef : (__bridge id) kCFBooleanTrue
                                  };
    
      // Now fetch the SecKeyRef version of the key
      SecKeyRef keyRef = nil;
      secStatus = SecItemCopyMatching((__bridge CFDictionaryRef)queryDict,
                                      (CFTypeRef *)&keyRef);
    
      if ( secStatus != noErr ) {
        return NULL;
      }
    
      return keyRef;
    }
    
    NSData *keyData = [[NSData alloc] initWithBase64EncodedString:@"base64encoded X509 private key"
                                                                  options:0];
    certificateData = [self stripPublicKeyHeader2:keyData];
    SecKeyRef key = [self publicKey:certificateData withTag:[[NSUUID UUID] UUIDString]];
    

    有点尴尬,不是我的代码,整天在谷歌上搜索,很多部分粘在一起。必须清理它,......把它当作从互联网编译的黑客。

    针对代码在 Java 中的服务器进行了测试,这是唯一的方法。我找到的唯一方法。也许还有其他方法,但只有这个对我有用,我可以用这个 RSA 公钥加密(我们的服务器代码(Java)可以解密它。它只在没有填充(不推荐)或@987654323 的情况下工作在 iOS 端使用 @ 填充,在 Java 端使用 RSA/NONE/OAEPWithSHA1AndMGF1Padding

    【讨论】:

      【解决方案2】:

      从 macOS 10.12、iOS/tvOS 10 和 watchOS 3 开始,现在可以使用 SecKeyCopyPublicKey 函数来执行此操作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-05-08
        • 1970-01-01
        • 2012-01-16
        • 1970-01-01
        • 2015-07-09
        • 2014-02-16
        • 1970-01-01
        相关资源
        最近更新 更多