SecKeyGetBlockSize does not actually return the block size
| Originator: | Karoly.Lorentey | ||
| Number: | rdar://10623794 | Date Originated: | 23-Dec-2011 03:45 PM |
| Status: | Open | Resolved: | |
| Product: | Mac OS X | Product Version: | 10.7.2 (11C73) |
| Classification: | Other Bug | Reproducible: | Always |
Summary:
SecKeyGetBlockSize is documented to return "the block length associated with the key in bytes." However, in reality it returns the logical key size, not the block length. The logical key size does not equal the block size for many of the symmetric key types. The function should be fixed to return correct values.
Furthermore, SecKeyGetBlockSize returns the key size in bits, not bytes. Either the documentation should be changed accordingly or the function should be fixed to return values in bytes. Returning the block size in bytes would be more helpful.
Steps to Reproduce:
Build and run the attached project. It creates an empty temporary keychain, and adds four symmetric keys and an asymmetric key pair to it (3DES, AES-128, AES-192, AES-256 and a 2048-bit RSA key pair). For all five keys, the result of SecKeyGetBlockSize is printed on the console.
Expected Results:
3DES block size is 64 bits, expected 8 bytes (64 bits)
AES-128 block size is 128 bits, expected 16 bytes (128 bits)
AES-192 block size is 128 bits, expected 16 bytes (128 bits)
AES-256 block size is 128 bits, expected 16 bytes (128 bits)
RSA block size is 2048 bits, expected 256 bytes (2048 bits)
Actual Results:
2011-12-23 15:27:21.000 KeychainBugs[43582:707] 3DES block size is 192 bits, expected 8 bytes (64 bits)
2011-12-23 15:27:21.058 KeychainBugs[43582:707] AES-128 block size is 128 bits, expected 16 bytes (128 bits)
2011-12-23 15:27:21.249 KeychainBugs[43582:707] AES-192 block size is 192 bits, expected 16 bytes (128 bits)
2011-12-23 15:27:21.265 KeychainBugs[43582:707] AES-256 block size is 256 bits, expected 16 bytes (128 bits)
2011-12-23 15:27:23.821 KeychainBugs[43582:707] RSA block size is 2048 bits, expected 256 bytes (2048 bits)
All results except AES-128 and RSA are wrong. AES-192 is particularly bad, because the returned value isn't even a multiple of the true block size.
Regression:
Unknown.
Notes:
#import <Foundation/Foundation.h>
#import <Security/Security.h>
static void ReportError(OSStatus status, NSString *message, ...) __attribute__((noreturn));
static void
ReportError(OSStatus status, NSString *message, ...)
{
va_list args;
va_start(args, message);
NSString *bakedMessage = [[[NSString alloc] initWithFormat:message arguments:args] autorelease];
va_end(args);
CFStringRef errorString = SecCopyErrorMessageString(status, NULL);
NSLog(@"%@: %@ (%d)", bakedMessage, (errorString ? (NSString *)errorString : @"unknown error"), (int)status);
if (errorString)
CFRelease(errorString);
exit(1);
}
static SecKeychainRef
MakeKeychain(NSString *path)
{
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
[[NSFileManager defaultManager] removeItemAtPath:path error:NULL];
}
SecKeychainRef keychain = NULL;
OSStatus status = SecKeychainCreate([path fileSystemRepresentation], 6, "foobar", NO, NULL, &keychain);
if (status)
ReportError(status, @"Can't create keychain");
[(id)keychain autorelease];
return keychain;
}
struct Keypair {
SecKeyRef publicKey;
SecKeyRef privateKey;
};
static struct Keypair
MakeRSAKeyPair(NSString *label, SecKeychainRef keychain)
{
OSStatus status;
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
[parameters setObject:kSecAttrKeyTypeRSA forKey:kSecAttrKeyType];
[parameters setObject:[NSNumber numberWithInt:2048] forKey:kSecAttrKeySizeInBits];
[parameters setObject:label forKey:kSecAttrLabel];
if (keychain) {
[parameters setObject:(id)keychain forKey:kSecUseKeychain];
[parameters setObject:(id)kCFBooleanTrue forKey:kSecAttrIsPermanent];
}
SecKeyRef spublicKey = NULL;
SecKeyRef sprivateKey = NULL;
status = SecKeyGeneratePair((CFDictionaryRef)parameters, &spublicKey, &sprivateKey);
if (status)
ReportError(status, @"Can't generate key pair");
[(id)spublicKey autorelease];
[(id)sprivateKey autorelease];
return (struct Keypair){ .publicKey = spublicKey, .privateKey = sprivateKey };
}
static SecKeyRef
Make3DESKey(NSString *label, SecKeychainRef keychain)
{
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
[parameters setObject:[NSNumber numberWithInt:192] forKey:kSecAttrKeySizeInBits];
[parameters setObject:kSecAttrKeyType3DES forKey:kSecAttrKeyType];
[parameters setObject:label forKey:kSecAttrLabel];
[parameters setObject:label forKey:kSecAttrApplicationTag];
if (keychain) {
[parameters setObject:(id)keychain forKey:kSecUseKeychain];
[parameters setObject:(id)kCFBooleanTrue forKey:kSecAttrIsPermanent];
}
CFErrorRef cferror = NULL;
SecKeyRef skey = SecKeyGenerateSymmetric((CFDictionaryRef)parameters, &cferror);
if (skey == NULL) {
ReportError((OSStatus)CFErrorGetCode(cferror), @"Can't generate symmetric key");
CFRelease(cferror);
}
[(id)skey autorelease];
return skey;
}
static SecKeyRef
MakeAESKey(NSString *label, int keySize, SecKeychainRef keychain)
{
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
[parameters setObject:[NSNumber numberWithInt:keySize] forKey:kSecAttrKeySizeInBits];
[parameters setObject:kSecAttrKeyTypeAES forKey:kSecAttrKeyType];
[parameters setObject:label forKey:kSecAttrLabel];
[parameters setObject:label forKey:kSecAttrApplicationTag];
if (keychain) {
[parameters setObject:(id)keychain forKey:kSecUseKeychain];
[parameters setObject:(id)kCFBooleanTrue forKey:kSecAttrIsPermanent];
}
CFErrorRef cferror = NULL;
SecKeyRef skey = SecKeyGenerateSymmetric((CFDictionaryRef)parameters, &cferror);
if (skey == NULL) {
ReportError((OSStatus)CFErrorGetCode(cferror), @"Can't generate symmetric key");
CFRelease(cferror);
}
[(id)skey autorelease];
return skey;
}
int
main (int argc, const char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *keychainPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"Test Keychain.keychain"];
SecKeychainRef keychain = MakeKeychain(keychainPath);
SecKeyRef tripleDESKey = Make3DESKey(@"Test key (3DES)", keychain);
SecKeyRef aes128Key = MakeAESKey(@"Test key (AES-128)", 128, keychain);
SecKeyRef aes192Key = MakeAESKey(@"Test key (AES-192)", 192, keychain);
SecKeyRef aes256Key = MakeAESKey(@"Test key (AES-256)", 256, keychain);
struct Keypair keypair = MakeRSAKeyPair(@"Test key (RSA)", keychain);
NSLog(@"3DES block size is %lu bits, expected 8 bytes (64 bits)", SecKeyGetBlockSize(tripleDESKey));
NSLog(@"AES-128 block size is %lu bits, expected 16 bytes (128 bits)", SecKeyGetBlockSize(aes128Key));
NSLog(@"AES-192 block size is %lu bits, expected 16 bytes (128 bits)", SecKeyGetBlockSize(aes192Key));
NSLog(@"AES-256 block size is %lu bits, expected 16 bytes (128 bits)", SecKeyGetBlockSize(aes256Key));
NSLog(@"RSA block size is %lu bits, expected 256 bytes (2048 bits)", SecKeyGetBlockSize(keypair.publicKey));
[pool drain];
return 0;
}
Comments
Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!