| /* |
| * |
| * Copyright (c) 2016-2017 Nest Labs, Inc. |
| * All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * @file |
| * This file implements a Wrapper for C++ implementation of pincode encryption/decryption functionality. |
| * for pin encryption. |
| * |
| */ |
| |
| #import "NLWeavePasscodeEncryptionSupport.h" |
| #include <Weave/Profiles/security/WeavePasscodes.h> |
| |
| using namespace nl::Weave::Profiles::Security::Passcodes; |
| |
| NSUInteger const NLWeavePasscode_Config1_TEST_ONLY = kPasscode_Config1_TEST_ONLY; |
| NSUInteger const NLWeavePasscode_Config2 = kPasscode_Config2; |
| |
| UInt8 const NLWeavePasscodeEncKeyDiversifier[] = { 0x1A, 0x65, 0x5D, 0x96 }; |
| UInt32 const NLWeavePasscodeEncKeyDiversifierSize = sizeof(NLWeavePasscodeEncKeyDiversifier); |
| UInt8 const NLWeavePasscodeFingerprintKeyDiversifier[] = { 0xD1, 0xA1, 0xD9, 0x6C }; |
| UInt32 const NLWeavePasscodeFingerprintKeyDiversifierSize = sizeof(NLWeavePasscodeFingerprintKeyDiversifier); |
| |
| UInt32 const NLWeavePasscodeEncryptionKeyLen = kPasscodeEncryptionKeyLen; |
| UInt32 const NLWeavePasscodeAuthenticationKeyLen = kPasscodeAuthenticationKeyLen; |
| UInt32 const NLWeavePasscodeFingerprintKeyLen = kPasscodeFingerprintKeyLen; |
| |
| NSString * const NLPasscodeEncryptionSupportDomain = @"NLPasscodeEncryptionSupportDomain"; |
| |
| @implementation NLWeavePasscodeEncryptionSupport |
| |
| #pragma mark Public Methods |
| |
| + (NSData *)encryptPasscode:(UInt8)config |
| keyId:(UInt32)keyId |
| nonce:(UInt32)nonce |
| passcode:(NSData *)passcode |
| encKey:(NSData *)encKey |
| authKey:(NSData *)authKey |
| fingerprintKey:(NSData *)fingerprintKey |
| error:(NSError **)errOut |
| { |
| |
| if (config != NLWeavePasscode_Config1_TEST_ONLY) { |
| if (![NLWeavePasscodeEncryptionSupport validateKeySize:encKey authKey:authKey fingerprintKey:fingerprintKey error:errOut]) { |
| return nil; |
| } |
| } |
| |
| NSMutableData * encPasscodeBuff = [[NSMutableData alloc] initWithLength:kPasscodeMaxEncryptedLen]; |
| size_t encPasscodeLen = 0; |
| |
| WEAVE_ERROR err = EncryptPasscode(config, keyId, nonce, (unsigned char *) [passcode bytes], [passcode length], |
| (unsigned char *) [encKey bytes], (unsigned char *) [authKey bytes], (unsigned char *) [fingerprintKey bytes], |
| (unsigned char *) [encPasscodeBuff mutableBytes], [encPasscodeBuff length], encPasscodeLen); |
| if (err != WEAVE_NO_ERROR) { |
| if (errOut) { |
| NSString * failureReason = [NSString stringWithFormat:NSLocalizedString(@"EncryptPasscode error: %d", @""), err]; |
| NSDictionary * userInfo = @{ NSLocalizedFailureReasonErrorKey : failureReason }; |
| |
| *errOut = [NSError errorWithDomain:NLPasscodeEncryptionSupportDomain |
| code:NLPasscodeEncryptionSupportDomainEncryptionFailure |
| userInfo:userInfo]; |
| } |
| return nil; |
| } |
| |
| [encPasscodeBuff setLength:encPasscodeLen]; |
| return encPasscodeBuff; |
| } |
| |
| + (nullable NSData *)decryptPasscode:(NSData *)encPasscode |
| config:(UInt8)config |
| encKey:(NSData *)encKey |
| authKey:(NSData *)authKey |
| fingerprintKey:(NSData *)fingerprintKey |
| error:(NSError **)errOut |
| { |
| |
| NSMutableData * passcodeBuff = [[NSMutableData alloc] initWithLength:kPasscodePaddedLen]; |
| size_t passcodeLen = 0; |
| |
| if (config != NLWeavePasscode_Config1_TEST_ONLY) { |
| if (![NLWeavePasscodeEncryptionSupport validateKeySize:encKey authKey:authKey fingerprintKey:fingerprintKey error:errOut]) { |
| return nil; |
| } |
| } |
| |
| WEAVE_ERROR err = DecryptPasscode((unsigned char *) [encPasscode bytes], [encPasscode length], (unsigned char *) [encKey bytes], |
| (unsigned char *) [authKey bytes], (unsigned char *) [fingerprintKey bytes], (unsigned char *) [passcodeBuff mutableBytes], |
| [passcodeBuff length], passcodeLen); |
| if (err != WEAVE_NO_ERROR) { |
| |
| NSString * failureReason = [NSString stringWithFormat:NSLocalizedString(@"DecryptPasscode error: %d", @""), err]; |
| NSDictionary * userInfo = @{ NSLocalizedFailureReasonErrorKey : failureReason }; |
| |
| *errOut = [NSError errorWithDomain:NLPasscodeEncryptionSupportDomain |
| code:NLPasscodeEncryptionSupportDomainDecryptionFailure |
| userInfo:userInfo]; |
| return nil; |
| } |
| |
| [passcodeBuff setLength:passcodeLen]; |
| return passcodeBuff; |
| } |
| |
| + (BOOL)isSupportedPasscodeEncryptionConfig:(UInt8)config |
| { |
| return IsSupportedPasscodeEncryptionConfig(config); |
| } |
| |
| + (BOOL)getEncryptedPasscodeConfig:(NSData *)encPasscode config:(UInt8 *)configOut error:(NSError **)errOut |
| { |
| UInt8 config = 0; |
| WEAVE_ERROR err = GetEncryptedPasscodeConfig((unsigned char *) [encPasscode bytes], [encPasscode length], config); |
| if (err != WEAVE_NO_ERROR) { |
| NSString * failureReason = |
| [NSString stringWithFormat:NSLocalizedString(@"retrieving encrypted config error: %d", @""), err]; |
| NSDictionary * userInfo = @{ NSLocalizedFailureReasonErrorKey : failureReason }; |
| |
| *errOut = [NSError errorWithDomain:NLPasscodeEncryptionSupportDomain |
| code:NLPasscodeEncryptionSupportDomainInvalidData |
| userInfo:userInfo]; |
| return FALSE; |
| } |
| *configOut = config; |
| |
| return TRUE; |
| } |
| + (BOOL)getEncryptedPasscodeKeyId:(NSData *)encPasscode keyId:(UInt32 *)keyIdOut error:(NSError **)errOut |
| { |
| UInt32 keyId = 0; |
| WEAVE_ERROR err = GetEncryptedPasscodeKeyId((unsigned char *) [encPasscode bytes], [encPasscode length], (uint32_t &) keyId); |
| if (err != WEAVE_NO_ERROR) { |
| NSString * failureReason = |
| [NSString stringWithFormat:NSLocalizedString(@"retrieving encrypted config error: %d", @""), err]; |
| NSDictionary * userInfo = @{ NSLocalizedFailureReasonErrorKey : failureReason }; |
| |
| *errOut = [NSError errorWithDomain:NLPasscodeEncryptionSupportDomain |
| code:NLPasscodeEncryptionSupportDomainInvalidData |
| userInfo:userInfo]; |
| return FALSE; |
| } |
| *keyIdOut = keyId; |
| |
| return TRUE; |
| } |
| |
| + (BOOL)getEncryptedPasscodeNonce:(NSData *)encPasscode nonce:(UInt32 *)nonceOut error:(NSError **)errOut |
| { |
| UInt32 nonce = 0; |
| WEAVE_ERROR err = GetEncryptedPasscodeNonce((unsigned char *) [encPasscode bytes], [encPasscode length], (uint32_t &) nonce); |
| if (err != WEAVE_NO_ERROR) { |
| NSString * failureReason = |
| [NSString stringWithFormat:NSLocalizedString(@"retrieving encrypted passcode nonce: %d", @""), err]; |
| NSDictionary * userInfo = @{ NSLocalizedFailureReasonErrorKey : failureReason }; |
| |
| *errOut = [NSError errorWithDomain:NLPasscodeEncryptionSupportDomain |
| code:NLPasscodeEncryptionSupportDomainInvalidData |
| userInfo:userInfo]; |
| return FALSE; |
| } |
| *nonceOut = nonce; |
| |
| return TRUE; |
| } |
| |
| + (nullable NSData *)getEncryptedPasscodeFingerprint:(NSData *)encPasscode error:(NSError **)errOut |
| { |
| |
| NSMutableData * fingerprint = [[NSMutableData alloc] initWithLength:kPasscodeFingerprintLen]; |
| size_t fingerprintLen = 0; |
| |
| WEAVE_ERROR err = GetEncryptedPasscodeFingerprint((unsigned char *) [encPasscode bytes], [encPasscode length], |
| (unsigned char *) [fingerprint mutableBytes], [fingerprint length], fingerprintLen); |
| if (err != WEAVE_NO_ERROR) { |
| |
| NSString * failureReason = [NSString stringWithFormat:NSLocalizedString(@"get fingerprint error: %d", @""), err]; |
| NSDictionary * userInfo = @{ NSLocalizedFailureReasonErrorKey : failureReason }; |
| |
| *errOut = [NSError errorWithDomain:NLPasscodeEncryptionSupportDomain |
| code:NLPasscodeEncryptionSupportDomainInvalidData |
| userInfo:userInfo]; |
| return nil; |
| } |
| |
| [fingerprint setLength:fingerprintLen]; |
| return fingerprint; |
| } |
| |
| #pragma mark Private Methods |
| |
| + (BOOL)validateKeySize:(NSData *)encKey authKey:(NSData *)authKey fingerprintKey:(NSData *)fingerprintKey error:(NSError **)errOut |
| { |
| |
| if ([encKey length] != kPasscodeEncryptionKeyLen) { |
| if (errOut) { |
| *errOut = [NSError errorWithDomain:NLPasscodeEncryptionSupportDomain |
| code:NLPasscodeEncryptionSupportDomainInvalidEncKeySize |
| userInfo:nil]; |
| } |
| return FALSE; |
| } |
| |
| if ([authKey length] != kPasscodeAuthenticationKeyLen) { |
| if (errOut) { |
| *errOut = [NSError errorWithDomain:NLPasscodeEncryptionSupportDomain |
| code:NLPasscodeEncryptionSupportDomainInvalidAuthKeySize |
| userInfo:nil]; |
| } |
| return FALSE; |
| } |
| |
| if ([fingerprintKey length] != kPasscodeFingerprintKeyLen) { |
| |
| if (errOut) { |
| *errOut = [NSError errorWithDomain:NLPasscodeEncryptionSupportDomain |
| code:NLPasscodeEncryptionSupportDomainInvalidFingerprintKeySize |
| userInfo:nil]; |
| } |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| @end |