【问题标题】:How to convert RSA key to ssh-rsa如何将 RSA 密钥转换为 ssh-rsa
【发布时间】:2015-09-08 23:49:21
【问题描述】:

我正在尝试使用 Apple 安全框架将生成的公共 RSA 密钥转换为 SSH。

这是我用来生成密钥对的代码:

- (void)generatePrivateKey {
    NSDictionary *privateKeyAttr = @{(__bridge id)kSecAttrIsPermanent: @YES,
                                     (__bridge id)kSecAttrApplicationTag: self.privateTag};
    NSDictionary *publicKeyAttr = @{(__bridge id)kSecAttrIsPermanent: @YES,
                                    (__bridge id)kSecAttrApplicationTag: self.publicTag};


    NSDictionary *keyPairAttr = @{(__bridge id)kSecAttrKeySizeInBits: @1024,
                                  (__bridge id)kSecAttrKeyType: (__bridge id)kSecAttrKeyTypeRSA,
                                  (__bridge id)kSecPrivateKeyAttrs: privateKeyAttr,
                                  (__bridge id)kSecPublicKeyAttrs: publicKeyAttr};

    SecKeyRef publicKey;
    SecKeyRef privateKey;

    SecKeyGeneratePair((__bridge CFDictionaryRef)keyPairAttr, &publicKey, &privateKey);
}

- (NSString *)getPublicKey {
    NSString *contents = [self keyForTag:self.publicTag];
    return [NSString stringWithFormat:@"-----BEGIN RSA PUBLIC KEY-----\n%@\n-----END RSA PUBLIC KEY-----", contents];
}

- (NSString *)getPrivateKey {
    NSString *contents = [self keyForTag:self.privateTag];
    return [NSString stringWithFormat:@"-----BEGIN RSA PRIVATE KEY-----\n%@\n-----END RSA PRIVATE KEY-----", contents];
}

- (NSString *)keyForTag:(NSData *)tag {
    NSDictionary *queryKey = @{(__bridge id)kSecClass: (__bridge id)kSecClassKey,
                                      (__bridge id)kSecAttrApplicationTag: tag,
                                      (__bridge id)kSecAttrKeyType: (__bridge id)kSecAttrKeyTypeRSA,
                                      (__bridge id)kSecReturnData: @YES};

    // Get the key bits.
    CFDataRef keyBits;
    OSStatus sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef)queryKey, (CFTypeRef *)&keyBits);
    NSData *passDat = (__bridge_transfer NSData *)keyBits;

    if (sanityCheck != noErr) {
        passDat = nil;
    }

    NSString *contents = [passDat base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
    return contents;
}

然后我得到一个这样的私钥:

-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQD0SvIfWFU1EzKD8rSUMWVcE9t52WtJCIKDyMPYiu3/VV9TBci7
7QocSl400yqjn5eX2piGRO5o/Wh/BKUdC/IzZbAb15jboKvgkE0R+EBnAs+zo2HJ
Y1sZwT4Bc9d1ClvhHpYdE9EwpPc1IIfsz+Sa41Z0wDXqWk90A33BqIcs3wIDAQAB
AoGBAMYvxx4G25mjaWgCjt1q9YAt2/COoqstbDTdu4UBsPNkn2ELYD6Vn440Bxlz
9zOnVaSsgvDrGz+x1gS2D/3woxtuqSHThEOQSHugbtDMEaZ7Pawrj7zVAZQ4PPhD
l9HNf4huhAnvDA9YE73rfQst4+vq0KpPjFHCKcEaQxLu7Y4BAkEB/UeBEdXbJ2e8
ReGmH11/glszpiS+MosJIk/d68la1B5A5gSw6MO4GHNzPUnsNVKJXPYKYPmLDP33
zrYXXXb/MQJAesyFhqM6TtY6IHXQyu43e6iemzAPjx2s9l0SgNAjH25JLS7tHcXo
2gA5JcA+LqS93ei/4lLwOCd7uX9qko2JDwJBARhfdT9MbQqUoaIXSE2cO8aYTyb4
s30/7hdlwNc+UzLUNQZtLrf2iDNt29OyDsiMV/NFwRECUPsmFndG6DYcfQECQHe/
ISZd3eoq9ZvZx7Vb/zbTA3eJsmJ5KcVElVqPnPB1d15cOFWkPKD5PsEVao3JkGzp
HtTw09euiPQm0CIBavkCQQC/GU6l+khFqewNmO5+cok6wSVpqw3paGL8bxIwgifT
yPv42Biyf3gmXtdP//tpyXPlzn6HPqf6PqFGEGvSpPDk
-----END RSA PRIVATE KEY-----

将其放入ssh-keygen 会生成以下公钥:

$ ssh-keygen -f test.p12 -y
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC7VWIi0kXyx/UCGG91iGqKjohRLIj9hp44Xwd/pIApBHo38/noUeqN07S4oGgx47zZthg3zKFP90eEdKKOXZ0yuQKOy+yB5YAYg7e9FVvxfXCOVrGaZohh37HLUql/bdOzTK6/Upjl0ZZNYpxWyfIZ/8jKCAaTG6BhPQhLmWxCQw==

我的问题是如何使用 Apple Security 框架或 OpenSSH 执行 ssh-keygen

更新:

我现在直接使用 OpenSSL 并获得一个有效的RSA 密钥。但是转换仍然无法正常工作:

- (NSString *)publicKey {
    RSA *rsa = self.rsaPrivateKey;

    // Encode the "ssh-rsa" string
    NSMutableData *sshrsa = [[NSMutableData alloc] init];
    const char start[] = {0, 0, 0, 7, 's', 's', 'h', '-', 'r', 's', 'a'};
    [sshrsa appendBytes:start length:sizeof(start)];

    // Encode the RSA encoding exponent e
    {
        const char *e = BN_bn2dec(rsa->e);
        NSString *length = [NSString stringWithFormat:@"%04lu", strlen(e)] ;
        [sshrsa appendData:[length dataUsingEncoding:NSUTF8StringEncoding]];
        [sshrsa appendBytes:e length:strlen(e)];
    }

    // Encode the RSA modul n
    {
        const char *n = BN_bn2dec(rsa->n);
        NSString *length = [NSString stringWithFormat:@"%04lu", strlen(n)] ;
        [sshrsa appendData:[length dataUsingEncoding:NSUTF8StringEncoding]];
        [sshrsa appendBytes:n length:strlen(n)];
    }

    return [sshrsa base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn];;
}

新密钥是

ssh-rsa AAAAB3NzaC1yc2EAAAAG4AAAATYwvdcavn8AALOV1CoAAAAG4HHTGr5/AAAwyNcavn8AAPAq1xq+fwAAkPBhBwEAAAC2hnJUVxt7AO3JLixNzOwBALilG75/AABQsaUbvn8AAJC2pRu+fwAAELGlG75/AABZVMwDAQAAAECupRu+fwAAsJsHXP9/AAAIC7kDAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHB3QAAAAAAA2IRA8A/wGr5/AAAAUvAavn8AAJBV4xq+fwAAAFLwGr5/AACQc4Ybvn8AAABS8Bq+fwAAAI4CHr5/AACQc4Ybvn8AAJBzhhu+fwAA4DGwG75/AACfAZIEAQAAAABS8Bq+fwAAUACBG75/AAA9j24JAQAAAFAAgRu+fwAAAFLwGr5/AADgMbAbvn8AAAAAAAAAAAAA4A==

这比它应该的要长得多:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC+gK0cEEgn/dDk+Sf/AdQtHp2rJoG7DxMuw2hL0+96rdKeixXVXWCE8GqMg7xIU8kSn0lrfcCJDhVBkArmlnlrZDfv1lTItBU7PvV4eDLT+3kApoqYMUmmo/ecDRyAaaOecoVZTl27RZghXcS7yxABlbVhYLzJEywOi46A9yBMFQ==

【问题讨论】:

  • 您能否更新一下您最终是如何生成 SSH 密钥的?我遇到了和你一样的问题;(

标签: objective-c encryption ssh openssl openssh


【解决方案1】:

Meta:至少是部分答案,但我不了解 ObjC,所以制作 CW 以进行改进。

注意:这几乎是 Convert pem key to ssh-rsa format 的副本,除了在 C 而非 ObjC 中,它从公钥文件而不是私钥文件开始——但 OpenSSL 的 RSA 密钥的内存结构是相同的公钥或私钥,公钥忽略特定于私钥的字段。 而且还可以改进。

您的代码(显然)生成一个 decimal 的长度值作为 4 位数字和一个 decimal 表示的幅度(没有符号,因为该值始终为正) e 和 n,但是 unbase64'ing 你发布的输出并没有显示结果中实际包含的任何这些,在匹配你的start 的正确初始部分之后似乎是垃圾,我不知道为什么。你可能需要一些 ObjC 调试帮助。

无论如何,正确的编码是 4 字节 binary(bigendian)长度,然后是二进制值的 binary bigendian 表示补码,这需要为 28k/2 到 28k-1 范围内的正数添加前导零字节;这通常是 n 的情况,因为 RSA 密钥大小通常选择 8 的倍数(实际上是 2 的幂或它的小倍数)。尽管可以,但很少以这种方式选择 e。请参阅https://www.rfc-editor.org/rfc/rfc4251#section-5 中的“字符串”和“mpint”。

您可以像 #1011572 中那样通过调用 BN_bn2bin 将二进制 bigendian 幅度放入一个足够大的缓冲区,然后将 4 字节长度、可能的 1 字节符号和幅度再次编码为一个大的 -足够的缓冲。或者 OpenSSL 实际上可以为您做很多事情;使用足够大的缓冲区调用BN_bn2mpi,它将计算长度、可能的符号和大小。

如何在 ObjC 中分配和管理缓冲区我留给你或其他人。请注意,长度字段和值部分都可以并且经常将零字节用作有效字节值;它不能被视为终结者或其他特殊的。用谷歌搜索一下,这可能NSString 来说是个问题,但我很容易出错。

【讨论】:

    【解决方案2】:

    无论ssh-keygen 做什么,它都可能是特定于 SSH 的,Apple 的安全框架可能不会涵盖这一点。

    可能值得检查一下ssh-keygen.c 中的do_print_publickey.c 中的write_key 做了什么,然后复制一下。

    或者考虑使用libssh2的libssh2_userauth_publickey_fromfile函数。

    【讨论】:

    • 我对我的问题进行了更新,因为它仍然无法正常工作。我不知道 ssh-keygen 在哪里进行转换。当我使用相同的代码时,我会得到完全不同的结果。
    猜你喜欢
    • 2010-11-03
    • 2014-11-27
    • 1970-01-01
    • 2011-03-10
    • 2020-07-05
    • 1970-01-01
    • 2015-01-21
    • 1970-01-01
    • 2011-03-06
    相关资源
    最近更新 更多