如何将RSA密钥转换为ssh-rsa [英] How to convert RSA key to ssh-rsa

查看:173
本文介绍了如何将RSA密钥转换为ssh-rsa的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to convert a generated public RSA key to a SSH using Apples security framework.

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

Here is the code I am using for generating the key pairs:

- (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;
}

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

Then I end up with a private key like this:

-----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会产生以下公共密钥:

Putting this into ssh-keygen produces the following public key:

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

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

My question is how to do the ssh-keygen with the Apple Security framework or OpenSSH?

更新:

我现在直接使用OpenSSL并获得有效的RSA密钥.但是,转换仍然无法正常进行:

I am now using OpenSSL directly and get a valid RSA key. However the conversion is still not working correctly:

- (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==

推荐答案

元:至少是答案的一部分,但我不了解ObjC,因此使CW有所改进.

Meta: At least part of an answer, but I don't know ObjC so making CW for improvement.

注意:这几乎是将pem密钥转换为ssh的副本-rsa格式,但使用C而不是ObjC,但它是从公钥文件而不是私钥文件开始的,但是RSA密钥的OpenSSL内存结构与公钥或私钥相同,带有私钥公钥忽略特定于字段的字段. 而且可以改进.

Note: This is nearly a duplicate of Convert pem key to ssh-rsa format except that is in C not ObjC, and it starts from a publickey file instead of a privatekey file -- but OpenSSL's in-memory structure for an RSA key is the same for a publickey or privatekey, with privatekey-specific fields ignored for a publickey. And it can be improved.

您的代码(显然)会为每个数字生成十进制的长度值(为4位数字)和大小的十进制表示形式(无符号,因为该值始终为正)的e和n,但是对发布的输出进行unbase64运算不会显示结果中实际包含的任何内容,在与您的start正确的初始部分匹配之后,这似乎是垃圾,我不知道为什么.您可能需要那里的ObjC调试帮助.

Your code (apparently) generates a length value in decimal as 4 digits and a decimal representation of the magnitude (without sign since the value is always positive) for each of e and n, but unbase64'ing your posted output doesn't show any of these actually included in the result, which after the correct initial part matching your start appears to be garbage, and I don't know why. You may need some ObjC debugging help there.

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

Anyway, the correct encoding is 4-byte binary (bigendian) length, followed by a binary bigendian representation of the value in two's complement, which requires adding a leading zero byte for a positive number in the range 28k/2 to 28k-1; this is usually the case for n because RSA key size is usually chosen a multiple of 8 (actually a power of 2 or small multiple thereof). e is rarely chosen this way although it can be. See "string" and "mpint" in https://tools.ietf.org/html/rfc4251#section-5 .

您可以像#1011572中那样,通过调用BN_bn2bin将二进制bigendian量级放入足够大的缓冲区中,然后对4字节长度,可能的1字节符号和量级进行编码,再将其编码为较大的-足够的缓冲区.或者,OpenSSL实际上可以为您做很多事情;用足够大的缓冲区调用BN_bn2mpi,它将执行长度,可能的符号和大小.

You can do this as in #1011572 by calling BN_bn2bin to get the binary bigendian magnitude into a large-enough buffer, then encode the 4-byte length, possible 1-byte sign and magnitude, again into a large-enough buffer. Or OpenSSL can actually do much of this for you; call BN_bn2mpi with a large-enough buffer and it will do the length, possible sign and magnitude.

如何在ObjC中分配和管理缓冲区?我留给您或其他人看.请注意,长度字段和值部分都可以并且经常将零字节用作有效字节值;不得将其视为终结符或其他特殊字符.稍加谷歌搜索对我来说,这可能对于NSString可能是个问题,但我很容易错了.

How to allocate and manage the buffer(s?) in ObjC I leave to you or someone else. Do note that both the length fields and the value parts can and frequently will use the zero byte as a valid byte value; it must not be treated as a terminator or otherwise special. A little googling suggests to me this may be a problem for NSString but I could easily be wrong.

这篇关于如何将RSA密钥转换为ssh-rsa的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆