使用安全转换验证使用Ruby/OpenSSL创建的RSA签名

使用安全转换验证使用Ruby/OpenSSL创建的RSA签名,ruby,cocoa,openssl,licensing,rsa,Ruby,Cocoa,Openssl,Licensing,Rsa,我正试图为我的应用程序实施一个简单的许可证密钥方案,但我遇到了严重的障碍。我在下面的例子 由于那篇博文是在2004年写的,而且OpenSSL在OSX上已被弃用,我正尝试使用Security Transforms API来完成许可证密钥验证,而不是OpenSSL。但是,我使用OpenSSL生成私钥和公钥;许可证密钥由Ruby web应用程序使用Ruby OpenSSL包装库从购买者电子邮件地址的SHA-256摘要中使用私钥生成 问题是,我所做的任何事情似乎都无法使用OpenSSL从Ruby生成安全

我正试图为我的应用程序实施一个简单的许可证密钥方案,但我遇到了严重的障碍。我在下面的例子

由于那篇博文是在2004年写的,而且OpenSSL在OSX上已被弃用,我正尝试使用Security Transforms API来完成许可证密钥验证,而不是OpenSSL。但是,我使用OpenSSL生成私钥和公钥;许可证密钥由Ruby web应用程序使用Ruby OpenSSL包装库从购买者电子邮件地址的SHA-256摘要中使用私钥生成

问题是,我所做的任何事情似乎都无法使用OpenSSL从Ruby生成安全转换API将验证的签名

我正在使用的Ruby代码是:

require('openssl')

# The email address used as the content of the license key.
license = 'test@example.com'

# Generate the public/private keypair.
`openssl genrsa -out private_key.pem 2048`
`openssl rsa -in conductor.pem -out public_key.data -pubout`

# Get the private key and a hash of the license.
private_key = OpenSSL::PKey::RSA.new(File.read('private_key.pem'))
signature   = OpenSSL::Digest::SHA256.digest(license)

# The signature passed to SecVerifyTransformCreate in the OS X app. I'm not sure which of these SecVerifyTransformCreate is expecting (the binary digest, a hex representation of the digest, or the original un-digested content), but none of them work.
signature_out = signature
#signature_out = OpenSSL::Digest::SHA256.hexdigest(license)
#signature_out = license

File.write('signature.data', signature_out)

# Sign the email address to generate the license key. Using the OpenSSL::PKey::PKey#sign method produces a license key that can only be verified on the command line by running:
#
#   echo -n test@example.com | openssl dgst -sha256 -sign test.pem
#
# while using the #private_encrypt method produces a key that can only be verified on the command line by running:
#
#   echo -n test@example.com | openssl dgst -sha256 -binary | openssl rsautl -sign -inkey test.pem
#
# I'm not sure what the exact difference between the two commands above is and why they correspond to the two different Ruby signing methods below. Neither approach produces something that SecVerifyTransformCreate will verify, however.
File.write('license_key.data',
           private_key.sign(OpenSSL::Digest::SHA256.new, license))
#           private_key.private_encrypt(signature))
以及Objective-C中相应的验证代码:

// Get the data.
NSData *publicKeyData  = [NSData dataWithContentsOfFile:@"public_key.data"];
NSData *signatureData  = [NSData dataWithContentsOfFile:@"signature.data"];
NSData *licenseKeyData = [NSData dataWithContentsOfFile:@"license_key.data"];

// Import the public key.
SecItemImportExportKeyParameters keyParameters = {};
SecExternalFormat format = kSecFormatOpenSSL;
SecExternalItemType type = kSecItemTypePublicKey;
CFArrayRef publicKeys;

SecItemImport((__bridge CFDataRef)publicKeyData,
              NULL,
              &format,
              &type,
              0,
              &keyParameters,
              NULL,
              &publicKeys);

NSArray *publicKeysArray = (__bridge_transfer NSArray *)publicKeys;
SecKeyRef publicKey = (__bridge SecKeyRef)publicKeysArray[0]; // TODO: How do we need to bridge this return value?

CFErrorRef error = NULL;

SecTransformRef verifier = SecVerifyTransformCreate(publicKey, (__bridge CFDataRef)signatureData, &error);

SecTransformSetAttribute(verifier, kSecTransformDebugAttributeName, kCFBooleanTrue, &error);
SecTransformSetAttribute(verifier, kSecTransformInputAttributeName, (__bridge CFDataRef)licenseKeyData, &error);
SecTransformSetAttribute(verifier, kSecDigestTypeAttribute, kSecDigestSHA2, &error);
SecTransformSetAttribute(verifier, kSecDigestLengthAttribute, (__bridge CFNumberRef)@256, &error);

// I'm not sure if one of these transform attributes is necessary, but neither of them produces a verified result anyways.
//  SecTransformSetAttribute(verifier, kSecInputIsAttributeName, kSecInputIsDigest, &error);
//  SecTransformSetAttribute(verifier, kSecInputIsAttributeName, kSecInputIsRaw, &error);

NSNumber *result = (__bridge NSNumber *)SecTransformExecute(verifier, &error);

NSLog(@"Result: %@", result);

有人知道我怎样才能做到这一点吗?我已经花了好几天的时间来达到我现在的状态,我已经用尽了我的能力来进一步调试它,所以如果有人有任何见解,我将不胜感激

简而言之,您混淆了一些关键概念。这里有一个快速入门介绍如何工作

  • 文档(许可证数据/电子邮件)用摘要(SHA256)散列
  • 私钥加密散列。这是二进制签名
  • 二进制签名需要编码成便于传输的格式,通常是base64或类似的文本
  • 编码的签名文档一起传递给验证方(您的objc应用程序)进行验证
  • 文档(您的许可证)使用相同的摘要再次散列(SHA256)
  • 编码的签名被解码回二进制
  • 公钥解密显示原始散列的签名
  • 如果此解密哈希与计算哈希匹配,则将其与计算哈希进行比较。验证文档
  • 在ruby方面,您混淆了签名和文档。您需要使用SHA256散列许可证,然后使用私钥加密该许可证以生成签名。您只是将文档的散列保存为签名。在ruby方面尝试一下:

    require 'openssl'
    require 'base64'
    
    license = 'test@example.com'
    private_key = OpenSSL::PKey::RSA.new(File.read('private_key.pem'))
    digest  = OpenSSL::Digest::SHA256.new
    signature = private_key.sign digest, license
    signature_out = Base64.encode64(signature)
    
    File.write('signature.data', signature_out)
    File.write('license_key.data', license) # no hash, no signing
    
    可以找到与此相关的ruby文档

    我对您在Objective-C方面使用的库不太熟悉,但这里的技巧是确保您在两端使用相同的摘要算法进行散列(SHA256),检查相同的加密算法(RSA)以及公钥和私钥是否兼容(匹配RSA模和公共指数),并对来回传递的二进制签名数据进行相同的编码(base64hex,等等)

    在ruby端,您正在使用SHA256生成签名,在objective-c上,您似乎正在使用SHA-2大小256验证签名,这样看起来就可以了

    解码签名(如果您正在从ruby编写二进制文件,可以跳过此步骤)

    对于您想要的验证,请参见:


    “由于那篇博文是在2004年写的,而且OpenSSL在OS X上已被弃用,我正试图使用Security Transforms API来完成许可证密钥验证,而不是OpenSSL。”-另一个选项是在OS X上构建OpenSSL 1.0.2版本,并改用它。有关在OS X上配置和构建的信息,请参阅OpenSSL wiki。感谢您的输入!如果我知道我现在知道的内容,并再次进行此操作,我肯定会链接到OpenSSL。但是,《加密服务指南》强烈建议您使用SecurCity Transforms API,我试图避免将另一个静态库链接到我的应用程序。此时,由于我已经用安全转换编写了大量代码,我希望找出缺少的部分是什么,而不是跳进切换到OpenSSL的兔子洞。“但是,《加密服务指南》强烈建议您使用安全转换API。。。“嗯,考虑……苹果并没有修复他们所有的安全漏洞,但是OpenSSL确实如此。例如,苹果安全传输的一些版本仍然有bug。并且只在最新操作系统的一个小版本中被修复。据我所知,OpenSSL修复了他们所有的bug(而且有时还有很多bug)。。非常感谢您详细且非常有用的回答!因此,长话短说确实是我混淆了签名和消息。一旦我交换了这两个,一切都很好!感谢您纠正了我的术语。如果不清楚,我对w你的定义让我更清楚了:)
    SecTransformRef decoder = SecDecodeTransformCreate(kSecBase64Encoding, &error);
    if (error) { CFShow(error); exit(-1); }
    
    SecTransformSetAttribute(decoder, 
                             kSecTransformInputAttributeName,
                             signatureData, 
                             &error);
    if (error) { CFShow(error); exit(-1); }
    
    CFDataRef signature = SecTransformExecute(decoder, &error);
    if (error) { CFShow(error); exit(-1); }
    
    verifier = SecVerifyTransformCreate(publicKey, signature, &error);
    if (error) { CFShow(error); exit(-1); } // show your errors!
    
    SecTransformSetAttribute(verifier,
                             kSecTransformInputAttributeName,
                             cfLicense,  // Converted from NSData
                             &error);
    if (error) { CFShow(error); exit(-1); }
    
    SecTransformSetAttribute(verifier, 
                             kSecDigestTypeAttribute, 
                             kSecDigestSHA2, 
                             &error);
    if (error) { CFShow(error); exit(-1); }
    
    SecTransformSetAttribute(verifier, 
                             kSecDigestLengthAttribute, 
                             (__bridge CFNumberRef)@256, 
                             &error);
    if (error) { CFShow(error); exit(-1); }
    
    result = SecTransformExecute(verifier, &error);
    if (error) { CFShow(error); exit(-1); }
    
    if (result == kCFBooleanTrue) {
      /* Signature was valid. */
    } else {
      /* Signature was invalid. */
    }