8 #import <Foundation/Foundation.h>
9 #import "KCSRPContext.h"
13 #include <corecrypto/ccsrp.h>
14 #include <corecrypto/ccsha2.h>
15 #include <corecrypto/ccdh_gp.h>
16 #include <corecrypto/ccder.h>
18 #import "NSError+KCCreationHelpers.h"
20 static const NSStringEncoding srpStringEncoding = NSUTF8StringEncoding;
22 @interface KCSRPContext ()
23 @property (readwrite) struct ccsrp_ctx* context;
24 @property (readwrite) struct ccrng_state *rng;
25 @property (readwrite) NSString* user;
28 @implementation KCSRPContext
30 + (KCSRPContext*) createWithUser: (NSString*) user
31 digestInfo: (const struct ccdigest_info *) di
32 group: (ccsrp_const_gp_t) gp
33 randomSource: (struct ccrng_state *) rng {
34 return [[self alloc] initWithUser:user
40 - (NSData*) dataForPassword: (NSString*) password {
41 return [password dataUsingEncoding:srpStringEncoding];
44 - (nullable const char *) userNameString {
45 return [self.user cStringUsingEncoding:srpStringEncoding];
48 - (instancetype) initWithUser: (NSString*) user
49 digestInfo: (const struct ccdigest_info *) di
50 group: (ccsrp_const_gp_t) gp
51 randomSource: (struct ccrng_state *) rng
55 self.context = malloc(ccsrp_sizeof_srp(di, gp));
56 ccsrp_ctx_init(self.context, di, gp);
64 #pragma clang diagnostic push
65 #pragma clang diagnostic ignored "-Wdeprecated-implementations"
67 ccsrp_ctx_clear(ccsrp_ctx_di(self.context),
68 ccsrp_ctx_gp(self.context),
73 #pragma clang diagnostic pop
76 size_t key_length = 0;
77 const void * key = ccsrp_get_session_key(self.context, &key_length);
79 return key ? [NSData dataWithBytesNoCopy:(void *)key length:key_length freeWhenDone:false] : nil;
82 - (bool) isAuthenticated {
83 return ccsrp_is_authenticated(self.context);
89 @implementation KCSRPClientContext
91 - (NSData*) copyStart: (NSError**) error {
92 NSMutableData* A_data = [NSMutableData dataWithLength: ccsrp_exchange_size(self.context)];
94 int result = ccsrp_client_start_authentication(self.context, self.rng, A_data.mutableBytes);
95 if (!CoreCryptoError(result, error, @"Start packet copy failed: %d", result)) {
102 static bool ExactDataSizeRequirement(NSData* data, NSUInteger expectedLength, NSError**error, NSString* name) {
103 return RequirementError(data.length == expectedLength, error, @"%@ incorrect size, Expected %ld, got %ld", name, (unsigned long)expectedLength, (unsigned long)data.length);
106 - (nullable NSData*) copyResposeToChallenge: (NSData*) B_data
107 password: (NSString*) password
109 error: (NSError**) error {
111 if (!ExactDataSizeRequirement(B_data, ccsrp_exchange_size(self.context), error, @"challenge data"))
114 NSMutableData* M_data = [NSMutableData dataWithLength: ccsrp_session_size(self.context)];
115 NSData* passwordData = [self dataForPassword: password];
117 int result = ccsrp_client_process_challenge(self.context,
118 [self userNameString],
124 M_data.mutableBytes);
126 if (!CoreCryptoError(result, error, @"Challenge processing failed: %d", result)) {
133 - (bool) verifyConfirmation: (NSData*) HAMK_data
134 error: (NSError**) error {
135 if (!ExactDataSizeRequirement(HAMK_data, ccsrp_session_size(self.context), error, @"confirmation data"))
138 return ccsrp_client_verify_session(self.context, HAMK_data.bytes);
143 @interface KCSRPServerContext ()
144 @property (readwrite) NSData* verifier;
147 @implementation KCSRPServerContext
149 - (bool) resetWithPassword: (NSString*) password
150 error: (NSError**) error {
151 const int salt_length = 16;
153 NSMutableData* salt = [NSMutableData dataWithLength: salt_length];
154 NSMutableData* verifier = [NSMutableData dataWithLength: ccsrp_ctx_sizeof_n(self.context)];
156 NSData* passwordData = [self dataForPassword: password];
158 int generateResult = ccsrp_generate_salt_and_verification(self.context,
160 [self userNameString],
165 verifier.mutableBytes);
167 if (!CoreCryptoError(generateResult, error, @"Error generating SRP salt/verifier")) {
171 self.verifier = verifier;
177 - (instancetype) initWithUser: (NSString*)user
178 password: (NSString*)password
179 digestInfo: (const struct ccdigest_info *) di
180 group: (ccsrp_const_gp_t) gp
181 randomSource: (struct ccrng_state *) rng {
182 self = [super initWithUser: user
187 if (![self resetWithPassword:password error:nil]) {
194 - (instancetype) initWithUser: (NSString*) user
196 verifier: (NSData*) verifier
197 digestInfo: (const struct ccdigest_info *) di
198 group: (ccsrp_const_gp_t) gp
199 randomSource: (struct ccrng_state *) rng {
200 self = [super initWithUser: user
205 self.verifier = verifier;
212 - (NSData*) copyChallengeFor: (NSData*) A_data
213 error: (NSError**) error {
214 if (!ExactDataSizeRequirement(A_data, ccsrp_exchange_size(self.context), error, @"start data"))
217 NSMutableData* B_data = [NSMutableData dataWithLength: ccsrp_exchange_size(self.context)];
219 int result = ccsrp_server_start_authentication(self.context, self.rng,
220 [self userNameString],
221 self.salt.length, self.salt.bytes,
222 self.verifier.bytes, A_data.bytes,
223 B_data.mutableBytes);
225 if (!CoreCryptoError(result, error, @"Server start authentication failed: %d", result)) {
232 - (NSData*) copyConfirmationFor: (NSData*) M_data
233 error: (NSError**) error {
234 if (!ExactDataSizeRequirement(M_data, ccsrp_session_size(self.context), error, @"response data"))
237 NSMutableData* HAMK_data = [NSMutableData dataWithLength: ccsrp_session_size(self.context)];
239 bool verify = ccsrp_server_verify_session(self.context, M_data.bytes, HAMK_data.mutableBytes);
241 if (!CoreCryptoError(!verify, error, @"SRP verification failed")) {