生物识别的基本逻辑:
1.需要在plist文件中添加 Privacy-Face ID Usage Description 属性
为了方便您快速登录,XXXXX需要访问您的面容 ID/指纹ID
#import <LocalAuthentication/LocalAuthentication.h>
/**
* 设备支持的生物验证方式
*/
typedef enum : NSUInteger {
/**
* 支持TouchID验证
*/
TDTouchIDSupperTypeTouchID = 1,
/**
* 支持FaceID验证
*/
TDTouchIDSupperTypeFaceID,
/**
* 不支持支持验证
*/
TDTouchIDSupperTypeNone,
} TDTouchIDSupperType;
/**
* TouchID 状态
*/
typedef enum : NSUInteger {
/**
* 当前设备不支持生物验证
*/
TDTouchIDStateNotSupport = 1,
/**
* 生物验证 验证成功
*/
TDTouchIDStateSuccess,
/**
* 生物验证 验证失败
*/
TDTouchIDStateFail,
/**
* 生物验证 被用户手动取消
*/
TDTouchIDStateUserCancel,
/**
* 用户不使用生物验证,选择手动输入密码
*/
TDTouchIDStateInputPassword,
/**
* 生物验证 被系统取消 (如遇到来电,锁屏,按了Home键等)
*/
TDTouchIDStateSystemCancel,
/**
* 生物验证 无法启动,因为用户没有设置密码
*/
TDTouchIDStatePasswordNotSet,
/**
* 生物验证 无法启动,因为用户没有设置生物验证
*/
TDTouchIDStateTouchIDNotSet,
/**
* 生物验证 无效
*/
TDTouchIDStateTouchIDNotAvailable,
/**
* 生物验证 被锁定(连续多次验证生物验证失败,系统需要用户手动输入密码)
*/
TDTouchIDStateTouchIDLockout,
/**
* 当前软件被挂起并取消了授权 (如App进入了后台等)
*/
TDTouchIDStateAppCancel,
/**
* 当前软件被挂起并取消了授权 (LAContext对象无效)
*/
TDTouchIDStateInvalidContext,
/**
* 系统版本不支持生物验证 (必须高于iOS 8.0才能使用)
*/
TDTouchIDStateVersionNotSupport,
/**
* 输入密码成功
*/
TDTouchIDStateInputPasswordSuccess,
/**
* 输入密码失败
*/
TDTouchIDStateInputPasswordFail,
/**
* 未注册
*/
TDTouchIDStateNotEnrolled,
} TDTouchIDState;
@interface TDTouchID : LAContext
typedef void (^StateBlock)(TDTouchIDState state,NSError *error);
+ (instancetype)sharedInstance;
/**
启动生物验证
@param desc Touch显示的描述
@param block 回调状态的block
*/
- (void)td_showTouchIDWithDescribe:(NSString *)desc BlockState:(StateBlock)block;
/**
启动生物验证
@param desc Touch显示的描述
@param faceDesc FaceID状态下显示的描述
@param block 回调状态的block
*/
- (void)td_showTouchIDWithDescribe:(NSString *)desc FaceIDDescribe:(NSString *)faceDesc BlockState:(StateBlock)block;
// 判断设备支持哪种认证方式 TouchID & FaceID
- (TDTouchIDSupperType)td_canSupperBiometrics;
@end
TDTouchID.m
#import "TDTouchID.h"
@implementation TDTouchID
+ (instancetype)sharedInstance {
static TDTouchID *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[TDTouchID alloc] init];
});
return instance;
}
- (void)td_showTouchIDWithDescribe:(NSString *)desc FaceIDDescribe:(NSString *)faceDesc BlockState:(StateBlock)block {
TDTouchIDSupperType supperType = [self td_canSupperBiometrics];
NSString *descStr;
// if (supperType == TDTouchIDSupperTypeTouchID && desc.length == 0) {
// descStr = @"通过Home键验证已有指纹";
// }else{
// descStr = desc;
// }
// if (supperType == TDTouchIDSupperTypeFaceID && faceDesc.length == 0) {
// descStr = @"通过已有面容ID验证";
// }else{
// descStr = faceDesc;
// }
if (supperType == TDTouchIDSupperTypeTouchID ) {
descStr = @"通过Home键验证已有指纹";
}else if (supperType == TDTouchIDSupperTypeFaceID) {
descStr = @"通过已有面容ID验证";
}else{
descStr = descStr;
}
if (NSFoundationVersionNumber < NSFoundationVersionNumber_iOS_8_0) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"系统版本不支持TouchID (必须高于iOS 8.0才能使用)");
block(TDTouchIDStateVersionNotSupport,nil);
});
return;
}
LAContext *context = [[LAContext alloc] init];
context.localizedFallbackTitle = @"输入密码";
NSError *error = nil;
if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:descStr reply:^(BOOL success, NSError * _Nullable error) {
if (success) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"TouchID 验证成功");
block(TDTouchIDStateSuccess,error);
});
}else if(error){
switch (error.code) {
case LAErrorAuthenticationFailed:{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"TouchID 验证失败");
block(TDTouchIDStateFail,error);
});
break;
}
case LAErrorUserCancel:{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"TouchID 被用户手动取消");
block(TDTouchIDStateUserCancel,error);
});
}
break;
case LAErrorUserFallback:{
dispatch_async(dispatch_get_main_queue(), ^{
NSInteger policy = LAPolicyDeviceOwnerAuthenticationWithBiometrics;
if ([UIDevice currentDevice].systemVersion.floatValue > 9.0) {
policy = LAPolicyDeviceOwnerAuthentication;
}
[context evaluatePolicy:policy localizedReason:@" " reply:^(BOOL success, NSError * _Nullable error) {
if (success) {
NSLog(@"TDTouchIDStateInputPasswordSuccess,选择手动输入密码");
block(TDTouchIDStateInputPasswordSuccess,error);
}else{
NSLog(@"用户不使用TouchID,选择手动输入密码");
switch (error.code) {
case LAErrorUserCancel:
NSLog(@"用户取消");
block(TDTouchIDStateUserCancel,error);
break;
case LAErrorPasscodeNotSet:
NSLog(@"没有设置密码");
block(TDTouchIDStatePasswordNotSet,error);
break;
default:
block(TDTouchIDStateInputPasswordFail,error);
break;
}
}
}];
});
// LAContext *context = [[LAContext alloc]init];
// [context evaluatePolicy:LAPolicyDeviceOwnerAuthentication localizedReason:@"输入密码" reply:^(BOOL success, NSError * _Nullable error) {
// if (success) {
// block(TDTouchIDStateInputPasswordSuccess,error);
// }else{
// block(TDTouchIDStateInputPasswordFail,error);
// }
// }];
// });
// block(TDTouchIDStateInputPassword,error);
}
break;
case LAErrorSystemCancel:{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"TouchID 被系统取消 (如遇到来电,锁屏,按了Home键等)");
block(TDTouchIDStateSystemCancel,error);
});
}
break;
case LAErrorPasscodeNotSet:{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"TouchID 无法启动,因为用户没有设置密码");
block(TDTouchIDStatePasswordNotSet,error);
});
}
break;
case LAErrorTouchIDNotEnrolled:{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"TouchID 无法启动,因为用户没有设置TouchID");
block(TDTouchIDStateTouchIDNotSet,error);
});
}
break;
case LAErrorTouchIDNotAvailable:{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"TouchID 无效");
block(TDTouchIDStateTouchIDNotAvailable,error);
});
}
break;
case LAErrorTouchIDLockout:{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"TouchID 被锁定(连续多次验证TouchID失败,系统需要用户手动输入密码)");
block(TDTouchIDStateTouchIDLockout,error);
});
}
break;
case LAErrorAppCancel:{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"当前软件被挂起并取消了授权 (如App进入了后台等)");
block(TDTouchIDStateAppCancel,error);
});
}
break;
case LAErrorInvalidContext:{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"当前软件被挂起并取消了授权 (LAContext对象无效)");
block(TDTouchIDStateInvalidContext,error);
});
}
break;
default:
break;
}
}
}];
}else{
NSLog(@"不支持指纹识别");
switch (error.code) {
case LAErrorBiometryNotEnrolled:
{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"TouchID is not enrolled TouchID未注册");
block(TDTouchIDStateTouchIDNotSet,error);
});
break;
}
case LAErrorPasscodeNotSet:
{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"A passcode has not been set 未设置密码");
block(TDTouchIDStatePasswordNotSet,error);
});
break;
}
case LAErrorTouchIDNotAvailable:{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"TouchID 无效");
block(TDTouchIDStateTouchIDNotAvailable,error);
});
}
break;
case LAErrorTouchIDLockout:{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"TouchID 被锁定(连续多次验证TouchID失败,系统需要用户手动输入密码)");
block(TDTouchIDStateTouchIDLockout,error);
});
}
break;
default:
{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"当前设备不支持TouchID");
block(TDTouchIDStateNotSupport,error);
});
break;
}
}
}
}
- (void)td_showTouchIDWithDescribe:(NSString *)desc BlockState:(StateBlock)block{
[self td_showTouchIDWithDescribe:desc FaceIDDescribe:nil BlockState:block];
}
// 判断设备支持哪种认证方式 TouchID & FaceID
- (TDTouchIDSupperType)td_canSupperBiometrics {
LAContext *context = [[LAContext alloc] init];
NSError *error;
if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
if (error != nil) {
return TDTouchIDSupperTypeNone;
}
if (@available(iOS 11.0, *)) {
return context.biometryType == LABiometryTypeTouchID ? TDTouchIDSupperTypeTouchID:TDTouchIDSupperTypeFaceID ;
}
}
return TDTouchIDSupperTypeNone;
}
@end
3.在需要的VC 进行调用
第一次设置指纹解锁/人脸识别解锁:
(1)获取授权成功之后,判断系统支持哪一种识别方式。
(2)验证成功之后,将随机生成的UUID + token + 公钥字符串 进行ECDSA签名;同时再把这个公钥字符串、token、UUID 传给后台,使该设备与用户绑定;绑定成功后可以将UUID及签名存下来
(3)登录的时候把UUID、签名过后的UUID传给后台 ,后台用公钥进行验签,验签成功即可登录账户。
第一次设置
#import <CommonCrypto/CommonDigest.h>
#import <LocalAuthentication/LAContext.h>
#import "TDTouchID.h"
#define Secp256r1CurveLen 256
unsigned char Secp256r1header[] =
{
0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02,
0x01, 0x06, 0x08, 0x2A, 0x86, 0x48,
0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03,
0x42, 0x00
};
#define Secp256r1headerLen 26
//随机生成UUID字符串
- (NSString *)uuidString
{
CFUUIDRef uuid_ref = CFUUIDCreate(NULL);
CFStringRef uuid_string_ref= CFUUIDCreateString(NULL, uuid_ref);
NSString *uuid = [NSString stringWithString:(__bridge NSString *)uuid_string_ref];
CFRelease(uuid_ref);
CFRelease(uuid_string_ref);
return [uuid lowercaseString];
}
//验证指纹识别/人脸识别
- (void)touchVerificationWithSwitch:(UISwitch *)btnSwitch {
DefinitionWeak(self);
if (btnSwitch.on == YES) {
TDTouchIDSupperType type = [[TDTouchID sharedInstance] td_canSupperBiometrics];
NSString * strTitle = (type==TDTouchIDSupperTypeFaceID?@"您尚未设置面容ID,请到设置中心设置您的面容ID":@"您尚未设置触控ID,请到设置中心设置您的触控ID");
[[TDTouchID sharedInstance] td_showTouchIDWithDescribe:@"通过Home键验证已有指纹" FaceIDDescribe:@"通过已有面容ID验证" BlockState:^(TDTouchIDState state, NSError *error) {
if (state == TDTouchIDStateNotSupport) { //不支持TouchID/FaceID
dispatch_async(dispatch_get_main_queue(), ^{
[btnSwitch setOn:NO];
[weak_self showMessage:@"当前设备不支持TouchID/FaceID"];
});
}else if (state == TDTouchIDStateSuccess) { //TouchID/FaceID验证成功
NSLog(@"jump");
dispatch_async(dispatch_get_main_queue(), ^{
[btnSwitch setOn:YES];
[weak_self requestRelationInfo];
});
}else if (state == TDTouchIDStateInputPasswordSuccess) {//密码输入成功
NSLog(@"jump");
dispatch_async(dispatch_get_main_queue(), ^{
[btnSwitch setOn:YES];
[weak_self requestRelationInfo];
});
}else if (state == TDTouchIDStateInputPasswordFail) {//密码输入取消 或者错误
dispatch_async(dispatch_get_main_queue(), ^{
[btnSwitch setOn:NO];
[weak_self showMessage:@"请稍后重试"];
});
} else if (state == TDTouchIDStateTouchIDNotSet) { // TouchID 无法启动,因为用户没有设置TouchID
NSLog(@"jump");
dispatch_async(dispatch_get_main_queue(), ^{
[btnSwitch setOn:NO];
});
[weak_self showAlertWithTitle:@"提示" message:strTitle cancelTitle:@"取消" okTitle:@"确定" completion:^(BOOL cancelled) {
if (cancelled) {
NSLog(@"确定");
//跳转到设置中心
NSURL *url = [NSURL URLWithString:@"App-Prefs:root=TOUCHID_PASSCODE"];
if ( [[UIApplication sharedApplication] canOpenURL: url] ) {
NSURL*url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
if (@available(iOS 10.0, *)){
[[UIApplication sharedApplication]openURL:url options:@{} completionHandler:^(BOOL success) {
}];
}else{
[[UIApplication sharedApplication] openURL:url];
}
}
};
}];
}else if (state == TDTouchIDStateInvalidContext) { //当前软件被挂起并取消了授权 (LAContext对象无效)")
dispatch_async(dispatch_get_main_queue(), ^{
[btnSwitch setOn:NO];
});
}else if (state == TDTouchIDStateAppCancel) { // 当前软件被挂起并取消了授权 (如App进入了后台等)
NSLog(@"jump");
dispatch_async(dispatch_get_main_queue(), ^{
[btnSwitch setOn:NO];
});
}else if (state == TDTouchIDStateTouchIDLockout) { // TouchID 被锁定(连续多次验证TouchID失败,系统需要用户手动输入密码)
dispatch_async(dispatch_get_main_queue(), ^{
[btnSwitch setOn:NO];
});
NSString *strMessage =[NSString stringWithFormat:@"%@被锁定,请稍后重试",(type==TDTouchIDSupperTypeFaceID)?@"面容ID":@"触控ID"];
[weak_self showAlertWithTitle:@"提示" message:strMessage cancelTitle:@"取消" okTitle:@"确定" completion:^(BOOL cancelled) {
if (cancelled) {
NSLog(@"确定");
};
}];
}else if (state == TDTouchIDStateTouchIDNotAvailable) { // TouchID 无效
dispatch_async(dispatch_get_main_queue(), ^{
[btnSwitch setOn:NO];
[weak_self showMessage:[NSString stringWithFormat:@"%@无效",(type==TDTouchIDSupperTypeFaceID)?@"面容ID":@"触控ID"]];
});
}else if (state == TDTouchIDStatePasswordNotSet) { // TouchID 无法启动,因为用户没有设置密码
dispatch_async(dispatch_get_main_queue(), ^{
[btnSwitch setOn:NO];
[weak_self showMessage:[NSString stringWithFormat:@"%@无法启动,因为您没有设置密码",(type==TDTouchIDSupperTypeFaceID)?@"面容ID":@"触控ID"]];
});
}else if (state == TDTouchIDStateSystemCancel) { // TouchID 被系统取消 (如遇到来电,锁屏,按了Home键等)
dispatch_async(dispatch_get_main_queue(), ^{
[btnSwitch setOn:NO];
});
}else if (state == TDTouchIDStateInputPassword) { // 用户不使用TouchID,选择手动输入密码
dispatch_async(dispatch_get_main_queue(), ^{
[btnSwitch setOn:NO];
});
}else if (state == TDTouchIDStateUserCancel) { //TouchID 被用户手动取消
dispatch_async(dispatch_get_main_queue(), ^{
[btnSwitch setOn:NO];
});
NSLog(@"TouchID 被用户手动取消");
}else if (state == TDTouchIDStateUserCancel) { //TDTouchIDStateFail
dispatch_async(dispatch_get_main_queue(), ^{
[btnSwitch setOn:NO];
});
NSLog(@"TouchID 验证失败");
}else{//其他所有状态都是no
dispatch_async(dispatch_get_main_queue(), ^{
[btnSwitch setOn:NO];
});
}
// ps:以上的状态处理并没有写完全!
// 在使用中你需要根据回调的状态进行处理,需要处理什么就处理什么
}];
}else{//关闭指纹识别
// [weak_self showMessage:@"关闭"];
}
}
//生成秘钥对
//产生密钥
- (void)generateKeyAsync {
CFErrorRef error = NULL;
NSString *kTag = @"com.smartee.online3";
SecAccessControlRef sacObject = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
// kSecAccessControlTouchIDAny |
kSecAccessControlPrivateKeyUsage, &error);
// Create parameters dictionary for key generation.
NSDictionary *parameters = @{
(id)kSecAttrTokenID: (id)kSecAttrTokenIDSecureEnclave,
(id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom,
(id)kSecAttrKeySizeInBits: @256,
(__bridge id)kSecAttrApplicationTag: kTag,//设置唯一表示 防止生成秘钥对失败
(__bridge id)kSecAttrKeyType: (__bridge id)kSecAttrKeyTypeECSECPrimeRandom,//表示产生ECC密钥对,注意目前只支持256位的ECC算法
(__bridge id)kSecAttrAccessible:(__bridge id)kSecAttrAccessibleAlways,//设置经常 防止生成秘钥对失败
(id)kSecAttrLabel: @"my-se-key",
(id)kSecPrivateKeyAttrs: @{
(id)kSecAttrAccessControl: (__bridge_transfer id)sacObject,
(id)kSecAttrIsPermanent: @YES,
}
};
//根据参数生成私钥
NSError *gen_error = nil;
SecKeyRef privateKey = (__bridge SecKeyRef)(CFBridgingRelease(SecKeyCreateRandomKey((__bridge CFDictionaryRef)parameters, (void *)&gen_error)));
// NSDictionary *params = @{
// (id)kSecClass: (id)kSecClassKey, (id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @256, (id)kSecAttrLabel: @"my-se-key", (id)kSecReturnRef: @YES, (id)kSecUseOperationPrompt: @"Authenticate to sign data" };
// SecKeyRef privateKey1;
// OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)params, (CFTypeRef *)&privateKey1);
//签名
// NSError *error1;
//提取公钥,进行验签,验签选择的算法必须与签名时的算法一致。
// id publicKey = CFBridgingRelease(SecKeyCopyPublicKey((SecKeyRef)privateKey1));
SecKeyRef publicKey = (__bridge SecKeyRef)(CFBridgingRelease(SecKeyCopyPublicKey((SecKeyRef)privateKey)));
//这里先把公钥保存到keychain才能拿到真正的公钥数据
NSDictionary *pubDict = @{
(__bridge id)kSecClass : (__bridge id)kSecClassKey,
(__bridge id)kSecAttrKeyType : (__bridge id)kSecAttrKeyTypeECSECPrimeRandom,
(__bridge id)kSecAttrLabel : @"my-se-key",
(__bridge id)kSecAttrIsPermanent : @(YES),
(__bridge id)kSecAttrKeySizeInBits: @256,
(__bridge id)kSecAttrApplicationTag: kTag,//设置唯一表示 防止生成秘钥对失败
(__bridge id)kSecAttrKeyType: (__bridge id)kSecAttrKeyTypeECSECPrimeRandom,//表示产生ECC密钥对,注意目前只支持256位的ECC算法
(__bridge id)kSecAttrAccessible:(__bridge id)kSecAttrAccessibleAlways,//设置经常 防止生成秘钥对失败
(__bridge id)kSecValueRef : (__bridge id)publicKey,
(__bridge id)kSecAttrKeyClass : (__bridge id)kSecAttrKeyClassPublic,
(__bridge id)kSecReturnData : @(YES)
};
CFTypeRef dataRef = NULL;
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)pubDict, &dataRef);
if(status == errSecSuccess){
NSLog(@"导出公钥成功");
NSData *publicKeyData = (__bridge NSData *)dataRef;
NSMutableData *data = [NSMutableData dataWithBytes:Secp256r1header
length:sizeof(Secp256r1header)];
[data appendData:publicKeyData];
NSString *strUUID = [self uuidString];
// NSString *strUUID =@"4fc669fc-ff96-48e2-873e-8f5ebe816103";
NSLog(@"strUUID ----%@",strUUID);
// NSString *publicStr = [publicKeyBits base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
NSString *publicStr = [data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
//去除空格 换行
NSString *publicStrKey = [self removeSpaceAndNewline:publicStr];
NSString *strToken = DSStringValue([UserDefaults objectForKey:@"Token"]);
NSString *strData = [NSString stringWithFormat:@"%@%@%@",strUUID,strToken,publicStrKey];
NSLog(@"strData ----%@",strData);
NSError *error;
NSData *dataToSign = [strData dataUsingEncoding:NSUTF8StringEncoding];
NSData *signature = CFBridgingRelease(SecKeyCreateSignature(privateKey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (CFDataRef)dataToSign, (void *)&error));
NSString *sign = [signature base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
NSString *signData = [self removeSpaceAndNewline:sign];
NSLog(@"sign ----%@",sign);
//设备签名
NSError *errorPrivate;
NSString *strUUIDNew = [self removeSpaceAndNewline:strUUID];
NSData *dataToSignPrivate = [strUUIDNew dataUsingEncoding:NSUTF8StringEncoding];
NSData *signaturePrivate = CFBridgingRelease(SecKeyCreateSignature(privateKey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (CFDataRef)dataToSignPrivate, (void *)&errorPrivate));
NSString *signUUID = [signaturePrivate base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
signUUID = [self removeSpaceAndNewline:signUUID];
NSLog(@"sign1 -----------%@",signUUID);
self.signUUid = signUUID;
self.strUUid = DSStringValue(strUUID);
NSLog(@"sign1 ----%@",signUUID);
//提取公钥,进行验签,验签选择的算法必须与签名时的算法一致。
// id publicKey = CFBridgingRelease(SecKeyCopyPublicKey((SecKeyRef)privateKey));
// Boolean verified = SecKeyVerifySignature((SecKeyRef)publicKey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (CFDataRef)dataToSign, (CFDataRef)signature, (void *)&error); if (verified == 1) {
// NSString * message = [NSString stringWithFormat:@"signature:%@ verified:%@ error:%@", signature, @"验签成功", error];
// NSLog(@"%@",message);
// }else{
// NSString * message = [NSString stringWithFormat:@"signature:%@ verified:%@ error:%@", signature, @"验签失败", error];
// NSLog(@"%@",message);
// }
NSLog(@"sign1sign1sign1 -----------%@",signData );
//提取公钥,进行验签,验签选择的算法必须与签名时的算法一致。
id publicKey = CFBridgingRelease(SecKeyCopyPublicKey((SecKeyRef)privateKey));
Boolean verified = SecKeyVerifySignature((SecKeyRef)publicKey, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (CFDataRef)dataToSign, (CFDataRef)signature, (void *)&error); if (verified == 1) {
NSString * message = [NSString stringWithFormat:@"signature:%@ verified:%@ error:%@", signature, @"验签成功", error];
NSLog(@"%@",message);
}else{
NSString * message = [NSString stringWithFormat:@"signature:%@ verified:%@ error:%@", signature, @"验签失败", error];
NSLog(@"%@",message);
}
dispatch_async(dispatch_get_main_queue(), ^{
//
[self grantFingerRequestWithArr:@[DSStringValue(strUUID),DSStringValue(strToken),DSStringValue(publicStrKey),DSStringValue(signData)]];;
//
});
}else{
NSLog(@"导出公钥失败");
}
}
//删除秘钥对
//删除密钥
- (void)deleteKeyAsync {
NSDictionary *query = @{
(__bridge id)kSecAttrTokenID: (__bridge id)kSecAttrTokenIDSecureEnclave,
(__bridge id)kSecClass: (__bridge id)kSecClassKey,
(__bridge id)kSecAttrKeyClass: (__bridge id)kSecAttrKeyClassPrivate,
(__bridge id)kSecAttrLabel: @"my-seec-key",
(__bridge id)kSecReturnRef: @YES,
};
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);
if(status == errSecSuccess){
NSLog(@"delete success");
}else{
NSLog(@"delete fail");
}
});
}
登录(若本地存有UUID 那么说明设置过 即可显示指纹登录/人脸登录按钮,并同时启动指纹/人脸登录;未存,则不显示、不启动)
- (void)verifyTouchIDInfo{
DefinitionWeak(self);
TDTouchIDSupperType type = [[TDTouchID sharedInstance] td_canSupperBiometrics];
NSString * strTitle = (type==TDTouchIDSupperTypeFaceID?@"您尚未设置面容ID,请到设置中心设置您的面容ID":@"您尚未设置触控ID,请到设置中心设置您的触控ID");
[[TDTouchID sharedInstance] td_showTouchIDWithDescribe:@"通过Home键验证已有指纹" FaceIDDescribe:@"通过已有面容ID验证" BlockState:^(TDTouchIDState state, NSError *error) {
if (state == TDTouchIDStateNotSupport) { //不支持TouchID/FaceID
dispatch_async(dispatch_get_main_queue(), ^{
[weak_self showMessage:@"当前设备不支持TouchID/FaceID"];
});
}else if (state == TDTouchIDStateSuccess) { //TouchID/FaceID验证成功
dispatch_async(dispatch_get_main_queue(), ^{
[weak_self requestFingerLoginInfo];
});
}else if (state == TDTouchIDStateInputPasswordSuccess) {//密码输入成功
NSLog(@"jump");
dispatch_async(dispatch_get_main_queue(), ^{
[weak_self requestFingerLoginInfo];
});
}else if (state == TDTouchIDStateInputPasswordFail) {//密码输入取消 或者错误
dispatch_async(dispatch_get_main_queue(), ^{
[self showMessage:@"请稍后重试"];
});
}else if (state == TDTouchIDStateTouchIDNotSet) { // TouchID 无法启动,因为用户没有设置TouchID
NSLog(@"jump");
[weak_self showAlertWithTitle:@"提示" message:strTitle cancelTitle:@"取消" okTitle:@"确定" completion:^(BOOL cancelled) {
if (cancelled) {
NSLog(@"确定");
//跳转到设置中心
// NSURL * url = [NSURL URLWithString: UIApplicationOpenSettingsURLString];
NSURL *url = [NSURL URLWithString:@"App-Prefs:root=TOUCHID_PASSCODE"];
if ( [[UIApplication sharedApplication] canOpenURL: url] ) {
NSURL*url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
if (@available(iOS 10.0, *)){
[[UIApplication sharedApplication]openURL:url options:@{} completionHandler:^(BOOL success) {
}];
}else{
[[UIApplication sharedApplication] openURL:url];
}
}
};
}];
}else if (state == TDTouchIDStateInvalidContext) { //当前软件被挂起并取消了授权 (LAContext对象无效)")
}else if (state == TDTouchIDStateAppCancel) { // 当前软件被挂起并取消了授权 (如App进入了后台等)
NSLog(@"jump");
}else if (state == TDTouchIDStateTouchIDLockout) { // TouchID 被锁定(连续多次验证TouchID失败,系统需要用户手动输入密码)
NSString *strMessage =[NSString stringWithFormat:@"%@被锁定,请稍后重试",(type==TDTouchIDSupperTypeFaceID)?@"面容ID":@"触控ID"];
[weak_self showAlertWithTitle:@"提示" message:strMessage cancelTitle:@"取消" okTitle:@"确定" completion:^(BOOL cancelled) {
if (cancelled) {
NSLog(@"确定");
};
}];
}else if (state == TDTouchIDStateTouchIDNotAvailable) { // TouchID 无效
dispatch_async(dispatch_get_main_queue(), ^{
[weak_self showMessage:[NSString stringWithFormat:@"%@无效",(type==TDTouchIDSupperTypeFaceID)?@"面容ID":@"触控ID"]];
});
}else if (state == TDTouchIDStatePasswordNotSet) { // TouchID 无法启动,因为用户没有设置密码
dispatch_async(dispatch_get_main_queue(), ^{
[weak_self showMessage:[NSString stringWithFormat:@"%@无法启动,因为您没有设置密码",(type==TDTouchIDSupperTypeFaceID)?@"面容ID":@"触控ID"]];
});
}else if (state == TDTouchIDStateSystemCancel) { // TouchID 被系统取消 (如遇到来电,锁屏,按了Home键等)
}else if (state == TDTouchIDStateInputPassword) { // 用户不使用TouchID,选择手动输入密码
}else if (state == TDTouchIDStateUserCancel) { //TouchID 被用户手动取消
NSLog(@"TouchID 被用户手动取消");
}else if (state == TDTouchIDStateFail) { //TDTouchIDStateFail
dispatch_async(dispatch_get_main_queue(), ^{
[weak_self showMessage:[NSString stringWithFormat:@"%@验证失败",(type==TDTouchIDSupperTypeFaceID)?@"面容ID":@"触控ID"]];
});
}else{//其他所有状态都是no
}
// ps:以上的状态处理并没有写完全!
// 在使用中你需要根据回调的状态进行处理,需要处理什么就处理什么
}];
}
参考文章:
1.ECDSA相关
2.验证签名及公钥是否有效
原文地址:https://blog.csdn.net/weixin_42050662/article/details/125222130
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_13675.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。