2 * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * SecPasswordStrength.c
29 #include <CoreFoundation/CoreFoundation.h>
30 #include <Security/SecItem.h>
31 #include <Security/SecBase.h>
32 #include <Security/SecRandom.h>
33 #include "SecPasswordGenerate.h"
34 #include <AssertMacros.h>
37 #include <utilities/SecCFWrappers.h>
38 #include <utilities/SecCFRelease.h>
39 #include <utilities/SecCFError.h>
41 // Keys for external dictionaries with password generation requirements we read from plist.
42 CFStringRef kSecPasswordMinLengthKey
= CFSTR("PasswordMinLength");
43 CFStringRef kSecPasswordMaxLengthKey
= CFSTR("PasswordMaxLength");
44 CFStringRef kSecPasswordAllowedCharactersKey
= CFSTR("PasswordAllowedCharacters");
45 CFStringRef kSecPasswordRequiredCharactersKey
= CFSTR("PasswordRequiredCharacters");
46 CFStringRef kSecPasswordDefaultForType
= CFSTR("PasswordDefaultForType");
48 CFStringRef kSecPasswordDisallowedCharacters
= CFSTR("PasswordDisallowedCharacters");
49 CFStringRef kSecPasswordCantStartWithChars
= CFSTR("PasswordCantStartWithChars");
50 CFStringRef kSecPasswordCantEndWithChars
= CFSTR("PasswordCantEndWithChars");
51 CFStringRef kSecPasswordContainsNoMoreThanNSpecificCharacters
= CFSTR("PasswordContainsNoMoreThanNSpecificCharacters");
52 CFStringRef kSecPasswordContainsAtLeastNSpecificCharacters
= CFSTR("PasswordContainsAtLeastNSpecificCharacters");
53 CFStringRef kSecPasswordContainsNoMoreThanNConsecutiveIdenticalCharacters
= CFSTR("PasswordContainsNoMoreThanNConsecutiveIdenticalCharacters");
54 CFStringRef kSecPasswordCharacterCount
= CFSTR("PasswordCharacterCount");
55 CFStringRef kSecPasswordCharacters
= CFSTR("PasswordCharacters");
57 CFStringRef kSecPasswordGroupSize
= CFSTR("PasswordGroupSize");
58 CFStringRef kSecPasswordNumberOfGroups
= CFSTR("PasswordNumberOfGroups");
59 CFStringRef kSecPasswordSeparator
= CFSTR("SecPasswordSeparator");
61 // Keys for internally used dictionaries with password generation parameters (never exposed to external API).
62 static CFStringRef kSecUseDefaultPasswordFormatKey
= CFSTR("UseDefaultPasswordFormat");
63 static CFStringRef kSecNumberOfRequiredRandomCharactersKey
= CFSTR("NumberOfRequiredRandomCharacters");
64 static CFStringRef kSecAllowedCharactersKey
= CFSTR("AllowedCharacters");
65 static CFStringRef kSecRequiredCharacterSetsKey
= CFSTR("RequiredCharacterSets");
67 static CFIndex defaultNumberOfRandomCharacters
= 20;
68 static CFIndex defaultPINLength
= 4;
69 static CFIndex defaultiCloudPasswordLength
= 24;
70 static CFIndex defaultWifiPasswordLength
= 12;
72 static CFStringRef defaultWifiCharacters
= CFSTR("abcdefghijklmnopqrstuvwxyz1234567890");
73 static CFStringRef defaultPINCharacters
= CFSTR("0123456789");
74 static CFStringRef defaultiCloudCharacters
= CFSTR("ABCDEFGHJKLMNPQRSTUVWXYZ23456789");
75 static CFStringRef defaultCharacters
= CFSTR("abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ123456789");
77 static CFCharacterSetRef uppercaseLetterCharacterSet
;
78 static CFCharacterSetRef lowercaseLetterCharacterSet
;
79 static CFCharacterSetRef decimalDigitCharacterSet
;
80 static CFCharacterSetRef punctuationCharacterSet
;
82 static CFIndex alphabetSetSize
= 26;
83 static CFIndex decimalSetSize
= 10;
84 static CFIndex punctuationSetSize
= 33;
85 static double entropyStrengthThreshold
= 35.0;
88 generated with ruby badpins.rb | gperf
89 See this for PIN list:
90 A birthday present every eleven wallets? The security of customer-chosen banking PINs (2012), by Joseph Bonneau , Sören Preibusch , Ross Anderson
92 const char *in_word_set (const char *str
, unsigned int len
);
94 #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
95 && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
96 && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
97 && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
98 && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
99 && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
100 && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
101 && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
102 && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
103 && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
104 && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
105 && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
106 && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
107 && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
108 && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
109 && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
110 && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
111 && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
112 && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
113 && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
114 && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
115 && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
116 && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
117 /* The character set is not based on ISO-646. */
118 error
"gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
122 #define TOTAL_KEYWORDS 100
123 #define MIN_WORD_LENGTH 4
124 #define MAX_WORD_LENGTH 4
125 #define MIN_HASH_VALUE 21
126 #define MAX_HASH_VALUE 275
127 /* maximum key range = 255, duplicates = 0 */
136 static unsigned int pinhash (const char *str
, unsigned int len
)
138 static unsigned short asso_values
[] =
140 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
141 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
142 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
143 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
144 276, 276, 276, 276, 276, 276, 276, 276, 5, 0,
145 10, 10, 30, 50, 100, 120, 70, 25, 57, 85,
146 2, 4, 1, 19, 14, 11, 92, 276, 276, 276,
147 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
148 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
149 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
150 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
151 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
152 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
153 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
154 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
155 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
156 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
157 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
158 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
159 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
160 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
161 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
162 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
163 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
164 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
165 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
166 276, 276, 276, 276, 276
168 return len
+ asso_values
[(unsigned char)str
[3]+9] + asso_values
[(unsigned char)str
[2]] + asso_values
[(unsigned char)str
[1]] + asso_values
[(unsigned char)str
[0]+3];
171 CFStringRef
SecPasswordCreateWithRandomDigits(int n
, CFErrorRef
*error
){
175 uppercaseLetterCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetUppercaseLetter
);
176 lowercaseLetterCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetLowercaseLetter
);
177 decimalDigitCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
);
178 punctuationCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetPunctuation
);
180 CFNumberRef minRef
= CFNumberCreate(NULL
, kCFNumberIntType
, &min
);
181 CFNumberRef maxRef
= CFNumberCreate(NULL
, kCFNumberIntType
, &max
);
183 CFMutableDictionaryRef passwordRequirements
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
184 CFDictionaryAddValue(passwordRequirements
, kSecPasswordMinLengthKey
, minRef
);
185 CFDictionaryAddValue(passwordRequirements
, kSecPasswordMaxLengthKey
, maxRef
);
186 CFStringRef allowedCharacters
= CFSTR("0123456789");
188 CFDictionaryAddValue(passwordRequirements
, kSecPasswordAllowedCharactersKey
, allowedCharacters
);
190 CFStringRef password
= SecPasswordGenerate(kSecPasswordTypePIN
, error
, passwordRequirements
);
192 CFReleaseNull(minRef
);
193 CFReleaseNull(maxRef
);
194 CFReleaseNull(passwordRequirements
);
201 //pins that reached the top 20 list
202 static const char *blacklist
[] = {"1234", "1004", "2000", "1122", "4321", "2001", "2580"};
203 bool SecPasswordIsPasswordWeak(CFStringRef passcode
)
205 uppercaseLetterCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetUppercaseLetter
);
206 lowercaseLetterCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetLowercaseLetter
);
207 decimalDigitCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
);
208 punctuationCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetPunctuation
);
210 bool isNumber
= true;
214 if( CFStringGetLength(passcode
) < 4 ){
215 return true; //weak password
217 //check to see if passcode is a number
218 for(CFIndex i
= 0; i
< CFStringGetLength(passcode
); i
++){
219 if( CFStringFindCharacterFromSet(passcode
, decimalDigitCharacterSet
, CFRangeMake(i
,1), 0, NULL
))
226 //checking to see if it's a 4 digit pin
227 if(isNumber
&& CFStringGetLength(passcode
) == 4){
229 pin
= CFStringToCString(passcode
);
230 if(in_word_set(pin
, 4)){
235 CFIndex blacklistLength
= (CFIndex
)sizeof(blacklist
)/sizeof(blacklist
[0]);
237 //not all the same number
238 if(pin
[0] == pin
[1] == pin
[2] == pin
[3]){
240 return true; //weak password
242 //first two digits being the same and the last two digits being the same
243 if ( pin
[0] == pin
[1] && pin
[2] == pin
[3]){
245 return true; //weak password
247 //first two digits not being the same as the last two digits
248 if(pin
[0] == pin
[2] && pin
[1] == pin
[3]){
250 return true; //weak password
253 for(CFIndex i
= 0; i
< blacklistLength
; i
++)
255 const char* blackCode
= blacklist
[i
];
256 if(0 == strcmp(blackCode
, pin
))
259 return true; //weak password
263 else if(isNumber
){ //dealing with a numeric PIN
264 pin
= CFStringToCString(passcode
);
265 //check if PIN is all the same number
266 for(int i
= 0; i
< CFStringGetLength(passcode
); i
++){
267 if(i
+1 >= CFStringGetLength(passcode
)){
271 else if (pin
[i
] == pin
[i
+1])
276 //check if PIN is a bunch of incrementing numbers
277 for(int i
= 0; i
< CFStringGetLength(passcode
); i
++){
278 if(i
== CFStringGetLength(passcode
)-1){
282 else if ((pin
[i
] + 1) == pin
[i
+1])
287 //check if PIN is a bunch of decrementing numbers
288 for(int i
= 0; i
< CFStringGetLength(passcode
); i
++){
289 if(i
== CFStringGetLength(passcode
)-1){
293 else if ((pin
[i
]) == (pin
[i
+1] +1))
299 else{ // password is complex, evaluate entropy
304 int characterSet
= 0;
306 //calculate new entropy
307 for(CFIndex i
= 0; i
< CFStringGetLength(passcode
); i
++){
309 if( CFStringFindCharacterFromSet(passcode
, uppercaseLetterCharacterSet
, CFRangeMake(i
,1), kCFCompareBackwards
, NULL
)){
313 if( CFStringFindCharacterFromSet(passcode
, lowercaseLetterCharacterSet
, CFRangeMake(i
,1), kCFCompareBackwards
, NULL
)){
317 if( CFStringFindCharacterFromSet(passcode
, decimalDigitCharacterSet
, CFRangeMake(i
,1), kCFCompareBackwards
, NULL
)){
321 if( CFStringFindCharacterFromSet(passcode
, punctuationCharacterSet
, CFRangeMake(i
,1), kCFCompareBackwards
, NULL
)){
328 characterSet
+= alphabetSetSize
;
331 characterSet
+= alphabetSetSize
;
334 characterSet
+= decimalSetSize
;
337 characterSet
+= punctuationSetSize
;
340 double strength
= CFStringGetLength(passcode
)*log2(characterSet
);
342 if(strength
< entropyStrengthThreshold
){
346 return false; //strong
351 return false; //strong password
355 static bool SecPasswordIsPasscodeIncrementingOrDecrementingDigits(CFStringRef passcode
)
357 char* pin
= CFStringToCString(passcode
);
359 //check if PIN is a bunch of incrementing numbers
360 for(int i
= 0; i
< CFStringGetLength(passcode
); i
++){
361 if(i
== CFStringGetLength(passcode
)-1){
365 else if ((pin
[i
] + 1) == pin
[i
+1])
370 //check if PIN is a bunch of decrementing numbers
371 for(int i
= 0; i
< CFStringGetLength(passcode
); i
++){
372 if(i
== CFStringGetLength(passcode
)-1){
376 else if ((pin
[i
]) == (pin
[i
+1] +1))
385 static bool SecPasswordIsPasswordRepeatingTwoNumbers(CFStringRef passcode
){
386 char* pin
= CFStringToCString(passcode
);
388 for(int i
= 0; i
< CFStringGetLength(passcode
); i
++)
390 if(i
+2 == CFStringGetLength(passcode
)-1){
394 else if(pin
[i
] == pin
[i
+2])
404 bool SecPasswordIsPasswordWeak2(bool isSimple
, CFStringRef passcode
)
406 uppercaseLetterCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetUppercaseLetter
);
407 lowercaseLetterCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetLowercaseLetter
);
408 decimalDigitCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
);
409 punctuationCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetPunctuation
);
415 if( CFStringGetLength(passcode
) < 4 ){
416 return true; //weak password
419 bool isPasscodeNumber
= true;
420 //check to see if passcode is a number
421 for(CFIndex i
= 0; i
< CFStringGetLength(passcode
); i
++){
422 if( CFStringFindCharacterFromSet(passcode
, decimalDigitCharacterSet
, CFRangeMake(i
,1), 0, NULL
))
425 isPasscodeNumber
= false;
431 //checking to see if it's a 4 digit pin
432 if(isPasscodeNumber
&& CFStringGetLength(passcode
) == 4){
434 pin
= CFStringToCString(passcode
);
435 if(in_word_set(pin
, 4)){
440 CFIndex blacklistLength
= (CFIndex
)sizeof(blacklist
)/sizeof(blacklist
[0]);
442 //not all the same number
443 if(pin
[0] == pin
[1] == pin
[2] == pin
[3]){
445 return true; //weak password
447 //first two digits being the same and the last two digits being the same
448 if ( pin
[0] == pin
[1] && pin
[2] == pin
[3]){
450 return true; //weak password
452 //first two digits not being the same as the last two digits
453 if(pin
[0] == pin
[2] && pin
[1] == pin
[3]){
455 return true; //weak password
458 for(CFIndex i
= 0; i
< blacklistLength
; i
++)
460 const char* blackCode
= blacklist
[i
];
461 if(0 == strcmp(blackCode
, pin
))
464 return true; //weak password
468 else if(isPasscodeNumber
&& CFStringGetLength(passcode
) == 6){
469 pin
= CFStringToCString(passcode
);
471 //not all the same number
472 for(int i
= 0; i
< CFStringGetLength(passcode
); i
++){
473 if(i
== CFStringGetLength(passcode
)-1){
477 else if ((pin
[i
]) == pin
[i
+1])
482 //passcode is incrementing ex 123456 or 654321
483 if(SecPasswordIsPasscodeIncrementingOrDecrementingDigits(passcode
)) {
487 //passcode does not consist of 2 repeating digits
488 if(SecPasswordIsPasswordRepeatingTwoNumbers(passcode
)){
493 else//should be a 4 or 6digit number
496 else if(isPasscodeNumber
&& !isSimple
){ //dealing with a complex numeric passcode
497 pin
= CFStringToCString(passcode
);
498 //check if PIN is all the same number
499 for(int i
= 0; i
< CFStringGetLength(passcode
); i
++){
500 if(i
+1 >= CFStringGetLength(passcode
)){
504 else if (pin
[i
] == pin
[i
+1])
509 if(SecPasswordIsPasscodeIncrementingOrDecrementingDigits(passcode
)) {
513 if(SecPasswordIsPasswordRepeatingTwoNumbers(passcode
)){
519 else{ // password is complex, evaluate entropy
524 int characterSet
= 0;
526 //calculate new entropy
527 for(CFIndex i
= 0; i
< CFStringGetLength(passcode
); i
++){
529 if( CFStringFindCharacterFromSet(passcode
, uppercaseLetterCharacterSet
, CFRangeMake(i
,1), kCFCompareBackwards
, NULL
)){
533 if( CFStringFindCharacterFromSet(passcode
, lowercaseLetterCharacterSet
, CFRangeMake(i
,1), kCFCompareBackwards
, NULL
)){
537 if( CFStringFindCharacterFromSet(passcode
, decimalDigitCharacterSet
, CFRangeMake(i
,1), kCFCompareBackwards
, NULL
)){
541 if( CFStringFindCharacterFromSet(passcode
, punctuationCharacterSet
, CFRangeMake(i
,1), kCFCompareBackwards
, NULL
)){
548 characterSet
+= alphabetSetSize
;
551 characterSet
+= alphabetSetSize
;
554 characterSet
+= decimalSetSize
;
557 characterSet
+= punctuationSetSize
;
560 double strength
= CFStringGetLength(passcode
)*log2(characterSet
);
562 if(strength
< entropyStrengthThreshold
){
566 return false; //strong
571 return false; //strong password
575 static void getUniformRandomNumbers(uint8_t* buffer
, size_t numberOfDesiredNumbers
, uint8_t upperBound
)
578 // The values returned by SecRandomCopyBytes are uniformly distributed in the range [0, 255]. If we try to map
579 // these values onto a smaller range using modulo we will introduce a bias towards lower numbers in situations
580 // where our smaller range doesn’t evenly divide in to [0, 255]. For example, with the desired range of [0, 54]
581 // the ranges 0..54, 55..109, 110..164, and 165..219 are uniformly distributed, but the range 220..255 modulo 55
582 // is only distributed over [0, 35], giving significant bias to these lower values. So, we ignore random numbers
583 // that would introduce this bias.
584 uint8_t limitAvoidingModuloBias
= UCHAR_MAX
- (UCHAR_MAX
% upperBound
);
586 for (size_t numberOfAcceptedNumbers
= 0; numberOfAcceptedNumbers
< numberOfDesiredNumbers
; ) {
587 if (SecRandomCopyBytes(kSecRandomDefault
, numberOfDesiredNumbers
- numberOfAcceptedNumbers
, buffer
+ numberOfAcceptedNumbers
) == -1)
589 for (size_t i
= numberOfAcceptedNumbers
; i
< numberOfDesiredNumbers
; ++i
) {
590 if (buffer
[i
] < limitAvoidingModuloBias
)
591 buffer
[numberOfAcceptedNumbers
++] = buffer
[i
] % upperBound
;
596 static bool passwordContainsRequiredCharacters(CFStringRef password
, CFArrayRef requiredCharacterSets
)
598 CFCharacterSetRef characterSet
;
600 for (CFIndex i
= 0; i
< CFArrayGetCount(requiredCharacterSets
); i
++) {
601 characterSet
= CFArrayGetValueAtIndex(requiredCharacterSets
, i
);
602 CFRange rangeToSearch
= CFRangeMake(0, CFStringGetLength(password
));
603 require_quiet(CFStringFindCharacterFromSet(password
, characterSet
, rangeToSearch
, 0, NULL
), fail
);
612 static bool passwordContainsLessThanNIdenticalCharacters(CFStringRef password
, CFIndex identicalCount
)
614 unsigned char Char
, nextChar
;
617 for(CFIndex i
= 0; i
< CFStringGetLength(password
); i
++){
618 Char
= CFStringGetCharacterAtIndex(password
, i
);
619 for(CFIndex j
= i
; j
< CFStringGetLength(password
); j
++){
620 nextChar
= CFStringGetCharacterAtIndex(password
, j
);
621 require_quiet(repeating
<= identicalCount
, fail
);
622 if(Char
== nextChar
){
635 static bool passwordContainsAtLeastNCharacters(CFStringRef password
, CFStringRef characters
, CFIndex N
)
637 CFCharacterSetRef characterSet
= NULL
;
638 characterSet
= CFCharacterSetCreateWithCharactersInString(kCFAllocatorDefault
, characters
);
641 for(CFIndex i
= 0; i
< CFStringGetLength(password
); i
++){
642 if(CFStringFindCharacterFromSet(password
, characterSet
, CFRangeMake(i
, 1), 0, NULL
))
645 CFReleaseNull(characterSet
);
652 static bool passwordContainsLessThanNCharacters(CFStringRef password
, CFStringRef characters
, CFIndex N
)
654 CFCharacterSetRef characterSet
= NULL
;
655 characterSet
= CFCharacterSetCreateWithCharactersInString(kCFAllocatorDefault
, characters
);
658 for(CFIndex i
= 0; i
< CFStringGetLength(password
); i
++){
659 if(CFStringFindCharacterFromSet(password
, characterSet
, CFRangeMake(i
, 1), 0, NULL
))
662 CFReleaseNull(characterSet
);
669 static bool passwordDoesNotContainCharacters(CFStringRef password
, CFStringRef prohibitedCharacters
)
671 CFCharacterSetRef characterSet
= NULL
;
672 characterSet
= CFCharacterSetCreateWithCharactersInString(kCFAllocatorDefault
, prohibitedCharacters
);
673 CFRange rangeToSearch
= CFRangeMake(0, CFStringGetLength(password
));
675 require_quiet(!CFStringFindCharacterFromSet(password
, characterSet
, rangeToSearch
, 0, NULL
), fail
);
676 CFReleaseNull(characterSet
);
679 CFReleaseNull(characterSet
);
683 static void getPasswordRandomCharacters(CFStringRef
*returned
, CFDictionaryRef requirements
, CFIndex
*numberOfRandomCharacters
, CFStringRef allowedCharacters
)
685 uint8_t randomNumbers
[*numberOfRandomCharacters
];
686 unsigned char randomCharacters
[*numberOfRandomCharacters
];
687 getUniformRandomNumbers(randomNumbers
, *numberOfRandomCharacters
, CFStringGetLength(allowedCharacters
));
689 CFTypeRef prohibitedCharacters
= NULL
;
690 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordDisallowedCharacters
, &prohibitedCharacters
))
691 prohibitedCharacters
= NULL
;
693 //it's faster for long characters to check each character produced for these cases
694 for (CFIndex i
= 0; i
< *numberOfRandomCharacters
; ++i
){
695 //check prohibited characters
696 UniChar randomChar
[1];
697 randomChar
[0] = CFStringGetCharacterAtIndex(allowedCharacters
, randomNumbers
[i
]);
698 if (prohibitedCharacters
!= NULL
)
700 CFStringRef temp
= CFStringCreateWithCharacters(kCFAllocatorDefault
, randomChar
, 1);
701 bool pwdncc
= passwordDoesNotContainCharacters(temp
, prohibitedCharacters
);
704 //change up the random numbers so we don't get the same index into allowed
705 getUniformRandomNumbers(randomNumbers
, *numberOfRandomCharacters
, CFStringGetLength(allowedCharacters
));
710 randomCharacters
[i
] = (unsigned char)randomChar
[0];
713 *returned
= CFStringCreateWithBytes(kCFAllocatorDefault
, randomCharacters
, *numberOfRandomCharacters
, kCFStringEncodingUTF8
, false);
716 static bool doesPasswordEndWith(CFStringRef password
, CFStringRef prohibitedCharacters
)
718 CFCharacterSetRef characterSet
= NULL
;
719 characterSet
= CFCharacterSetCreateWithCharactersInString(kCFAllocatorDefault
, prohibitedCharacters
);
721 CFRange rangeToSearch
= CFRangeMake(CFStringGetLength(password
) - CFStringGetLength(prohibitedCharacters
), CFStringGetLength(prohibitedCharacters
));
722 require_quiet(0 == CFStringCompareWithOptions(password
, prohibitedCharacters
, rangeToSearch
, 0), fail
);
723 CFReleaseNull(characterSet
);
726 CFReleaseNull(characterSet
);
730 static bool doesPasswordStartWith(CFStringRef password
, CFStringRef prohibitedCharacters
)
732 CFCharacterSetRef characterSet
= NULL
;
733 characterSet
= CFCharacterSetCreateWithCharactersInString(kCFAllocatorDefault
, prohibitedCharacters
);
735 CFRange rangeToSearch
= CFRangeMake(0, CFStringGetLength(prohibitedCharacters
));
736 require_quiet(0 == CFStringCompareWithOptions(password
, prohibitedCharacters
, rangeToSearch
, 0), fail
);
737 CFReleaseNull(characterSet
);
738 return false; //does not start with prohibitedCharacters
740 CFReleaseNull(characterSet
);
744 static CFDictionaryRef
passwordGenerateCreateDefaultParametersDictionary(SecPasswordType type
, CFDictionaryRef requirements
){
746 CFMutableArrayRef requiredCharacterSets
= NULL
;
747 CFNumberRef numReqChars
= NULL
;
748 CFStringRef defaultPasswordFormat
= NULL
;
749 requiredCharacterSets
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
750 defaultPasswordFormat
= CFSTR("true");
751 CFTypeRef groupSizeRef
= NULL
, numberOfGroupsRef
= NULL
;
752 CFIndex groupSize
, numberOfGroups
;
753 CFDictionaryRef returned
= NULL
;
756 case(kSecPasswordTypeiCloudRecovery
):
757 numReqChars
= CFNumberCreateWithCFIndex(kCFAllocatorDefault
, defaultiCloudPasswordLength
);
760 groupSizeRef
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &groupSize
);
761 numberOfGroupsRef
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &numberOfGroups
);
763 uppercaseLetterCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetUppercaseLetter
);
764 decimalDigitCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
);
765 CFArrayAppendValue(requiredCharacterSets
, uppercaseLetterCharacterSet
);
766 CFArrayAppendValue(requiredCharacterSets
, decimalDigitCharacterSet
);
767 returned
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
768 kSecUseDefaultPasswordFormatKey
, defaultPasswordFormat
,
769 kSecNumberOfRequiredRandomCharactersKey
, numReqChars
,
770 kSecAllowedCharactersKey
, defaultiCloudCharacters
,
771 kSecRequiredCharacterSetsKey
, requiredCharacterSets
,
772 kSecPasswordGroupSize
, groupSizeRef
,
773 kSecPasswordNumberOfGroups
, numberOfGroupsRef
,
777 case(kSecPasswordTypePIN
):
778 numReqChars
= CFNumberCreateWithCFIndex(kCFAllocatorDefault
, defaultPINLength
);
781 groupSizeRef
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &groupSize
);
782 numberOfGroupsRef
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &numberOfGroups
);
784 decimalDigitCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
);
785 CFArrayAppendValue(requiredCharacterSets
, decimalDigitCharacterSet
);
786 returned
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
787 kSecUseDefaultPasswordFormatKey
, defaultPasswordFormat
,
788 kSecNumberOfRequiredRandomCharactersKey
, numReqChars
,
789 kSecAllowedCharactersKey
, defaultPINCharacters
,
790 kSecRequiredCharacterSetsKey
, requiredCharacterSets
,
791 kSecPasswordGroupSize
, groupSizeRef
,
792 kSecPasswordNumberOfGroups
, numberOfGroupsRef
,
796 case(kSecPasswordTypeWifi
):
799 groupSizeRef
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &groupSize
);
800 numberOfGroupsRef
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &numberOfGroups
);
802 lowercaseLetterCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetLowercaseLetter
);
803 decimalDigitCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
);
805 numReqChars
= CFNumberCreateWithCFIndex(kCFAllocatorDefault
, defaultWifiPasswordLength
);
806 CFArrayAppendValue(requiredCharacterSets
, lowercaseLetterCharacterSet
);
807 CFArrayAppendValue(requiredCharacterSets
, decimalDigitCharacterSet
);
808 returned
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
809 kSecUseDefaultPasswordFormatKey
, defaultPasswordFormat
,
810 kSecNumberOfRequiredRandomCharactersKey
, numReqChars
,
811 kSecAllowedCharactersKey
, defaultWifiCharacters
,
812 kSecRequiredCharacterSetsKey
, requiredCharacterSets
,
813 kSecPasswordGroupSize
, groupSizeRef
,
814 kSecPasswordNumberOfGroups
, numberOfGroupsRef
,
821 groupSizeRef
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &groupSize
);
822 numberOfGroupsRef
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &numberOfGroups
);
823 uppercaseLetterCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetUppercaseLetter
);
824 lowercaseLetterCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetLowercaseLetter
);
825 decimalDigitCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
);
826 CFArrayAppendValue(requiredCharacterSets
, uppercaseLetterCharacterSet
);
827 CFArrayAppendValue(requiredCharacterSets
, lowercaseLetterCharacterSet
);
828 CFArrayAppendValue(requiredCharacterSets
, decimalDigitCharacterSet
);
830 numReqChars
= CFNumberCreateWithCFIndex(kCFAllocatorDefault
, defaultNumberOfRandomCharacters
);
831 returned
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
832 kSecUseDefaultPasswordFormatKey
, defaultPasswordFormat
,
833 kSecNumberOfRequiredRandomCharactersKey
, numReqChars
,
834 kSecAllowedCharactersKey
, defaultCharacters
,
835 kSecRequiredCharacterSetsKey
, requiredCharacterSets
,
836 kSecPasswordGroupSize
, groupSizeRef
,
837 kSecPasswordNumberOfGroups
, numberOfGroupsRef
,
845 CFReleaseNull(numReqChars
);
846 CFReleaseNull(requiredCharacterSets
);
847 CFReleaseNull(groupSizeRef
);
848 CFReleaseNull(numberOfGroupsRef
);
851 static CFDictionaryRef
passwordGenerationCreateParametersDictionary(SecPasswordType type
, CFDictionaryRef requirements
)
853 CFMutableArrayRef requiredCharacterSets
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
854 CFArrayRef requiredCharactersArray
= NULL
;
855 CFNumberRef numReqChars
= NULL
;
856 CFIndex numberOfRequiredRandomCharacters
;
857 CFStringRef allowedCharacters
= NULL
, useDefaultPasswordFormat
= NULL
;
859 CFTypeRef prohibitedCharacters
= NULL
, endWith
= NULL
, startWith
= NULL
,
860 groupSizeRef
= NULL
, numberOfGroupsRef
= NULL
, separatorRef
= NULL
,
861 atMostCharactersRef
= NULL
,atLeastCharactersRef
= NULL
, identicalRef
= NULL
;
863 CFNumberRef min
= (CFNumberRef
)CFDictionaryGetValue(requirements
, kSecPasswordMinLengthKey
);
864 CFNumberRef max
= (CFNumberRef
)CFDictionaryGetValue(requirements
, kSecPasswordMaxLengthKey
);
866 CFNumberGetValue(min
, kCFNumberSInt64Type
, &valuePtr
);
867 CFIndex minPasswordLength
= (long)valuePtr
;
868 CFNumberGetValue(max
, kCFNumberSInt64Type
, &valuePtr
);
869 CFIndex maxPasswordLength
= (long)valuePtr
;
871 // If requirements allow, we will generate the password in default format.
872 useDefaultPasswordFormat
= CFSTR("true");
873 numberOfRequiredRandomCharacters
= defaultNumberOfRandomCharacters
;
875 if(type
== kSecPasswordTypePIN
)
877 if( maxPasswordLength
&& minPasswordLength
)
878 numberOfRequiredRandomCharacters
= maxPasswordLength
;
879 else if( !maxPasswordLength
&& minPasswordLength
)
880 numberOfRequiredRandomCharacters
= minPasswordLength
;
881 else if( !minPasswordLength
&& maxPasswordLength
)
882 numberOfRequiredRandomCharacters
= maxPasswordLength
;
884 numberOfRequiredRandomCharacters
= defaultPINLength
;
886 allowedCharacters
= CFSTR("0123456789");
887 CFArrayAppendValue(requiredCharacterSets
, decimalDigitCharacterSet
);
888 requiredCharactersArray
= CFArrayCreateCopy(NULL
, requiredCharacterSets
);
889 useDefaultPasswordFormat
= CFSTR("false");
892 if (minPasswordLength
&& minPasswordLength
> defaultNumberOfRandomCharacters
) {
893 useDefaultPasswordFormat
= CFSTR("false");
894 numberOfRequiredRandomCharacters
= minPasswordLength
;
896 if (maxPasswordLength
&& maxPasswordLength
< defaultNumberOfRandomCharacters
) {
897 useDefaultPasswordFormat
= CFSTR("false");
898 numberOfRequiredRandomCharacters
= maxPasswordLength
;
900 if (maxPasswordLength
&& minPasswordLength
&& maxPasswordLength
== minPasswordLength
&& maxPasswordLength
!= defaultNumberOfRandomCharacters
){
901 useDefaultPasswordFormat
= CFSTR("false");
902 numberOfRequiredRandomCharacters
= maxPasswordLength
;
904 allowedCharacters
= (CFStringRef
)CFDictionaryGetValue(requirements
, kSecPasswordAllowedCharactersKey
);
905 requiredCharactersArray
= (CFArrayRef
)CFDictionaryGetValue(requirements
, kSecPasswordRequiredCharactersKey
);
907 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordDisallowedCharacters
, &prohibitedCharacters
))
908 prohibitedCharacters
= NULL
;
910 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordCantEndWithChars
, &endWith
))
913 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordCantStartWithChars
, &startWith
))
916 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordGroupSize
, &groupSizeRef
))
919 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordNumberOfGroups
, &numberOfGroupsRef
))
920 numberOfGroupsRef
= NULL
;
922 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordSeparator
, &separatorRef
))
925 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordContainsNoMoreThanNSpecificCharacters
, &atMostCharactersRef
))
926 atMostCharactersRef
= NULL
;
928 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordContainsAtLeastNSpecificCharacters
, &atLeastCharactersRef
))
929 atLeastCharactersRef
= NULL
;
931 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordContainsNoMoreThanNConsecutiveIdenticalCharacters
, &identicalRef
))
934 if (allowedCharacters
) {
935 if( false == CFStringFindWithOptions(allowedCharacters
, CFSTR("-"), CFRangeMake(0, CFStringGetLength(allowedCharacters
)), kCFCompareCaseInsensitive
, NULL
))
936 useDefaultPasswordFormat
= CFSTR("false");
938 allowedCharacters
= defaultCharacters
;
940 // In default password format, we use dashes only as separators, not as symbols you can encounter at a random position.
941 if (useDefaultPasswordFormat
== CFSTR("false")){
942 CFMutableStringRef mutatedAllowedCharacters
= CFStringCreateMutableCopy(kCFAllocatorDefault
, CFStringGetLength(allowedCharacters
), allowedCharacters
);
943 CFStringFindAndReplace (mutatedAllowedCharacters
, CFSTR("-"), CFSTR(""), CFRangeMake(0, CFStringGetLength(allowedCharacters
)),kCFCompareCaseInsensitive
);
944 allowedCharacters
= CFStringCreateCopy(kCFAllocatorDefault
, mutatedAllowedCharacters
);
947 if (requiredCharactersArray
) {
948 for (CFIndex i
= 0; i
< CFArrayGetCount(requiredCharactersArray
); i
++){
949 CFCharacterSetRef stringWithRequiredCharacters
= CFArrayGetValueAtIndex(requiredCharactersArray
, i
);
950 if(stringWithRequiredCharacters
&& CFStringFindCharacterFromSet(allowedCharacters
, stringWithRequiredCharacters
, CFRangeMake(0, CFStringGetLength(allowedCharacters
)), 0, NULL
)){
951 CFArrayAppendValue(requiredCharacterSets
, stringWithRequiredCharacters
);
955 uppercaseLetterCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetUppercaseLetter
);
956 lowercaseLetterCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetLowercaseLetter
);
957 decimalDigitCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
);
958 CFArrayAppendValue(requiredCharacterSets
, uppercaseLetterCharacterSet
);
959 CFArrayAppendValue(requiredCharacterSets
, lowercaseLetterCharacterSet
);
960 CFArrayAppendValue(requiredCharacterSets
, decimalDigitCharacterSet
);
964 if (CFArrayGetCount(requiredCharacterSets
) > numberOfRequiredRandomCharacters
) {
965 CFReleaseNull(requiredCharacterSets
);
966 requiredCharacterSets
= NULL
;
968 //create new CFDictionary
969 numReqChars
= CFNumberCreateWithCFIndex(kCFAllocatorDefault
, numberOfRequiredRandomCharacters
);
970 CFMutableDictionaryRef updatedConstraints
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
971 CFDictionaryAddValue(updatedConstraints
, kSecUseDefaultPasswordFormatKey
, useDefaultPasswordFormat
);
972 CFDictionarySetValue(updatedConstraints
, kSecNumberOfRequiredRandomCharactersKey
, numReqChars
);
973 CFDictionaryAddValue(updatedConstraints
, kSecAllowedCharactersKey
, allowedCharacters
);
974 if(requiredCharacterSets
)
975 CFDictionaryAddValue(updatedConstraints
, kSecRequiredCharacterSetsKey
, requiredCharacterSets
);
977 //add the prohibited characters string if it exists to the new dictionary
978 if(prohibitedCharacters
)
979 CFDictionaryAddValue(updatedConstraints
, kSecPasswordDisallowedCharacters
, prohibitedCharacters
);
981 //add the characters the password can't end with if it exists to the new dictionary
983 CFDictionaryAddValue(updatedConstraints
, kSecPasswordCantEndWithChars
, endWith
);
985 //add the characters the password can't start with if it exists to the new dictionary
987 CFDictionaryAddValue(updatedConstraints
, kSecPasswordCantStartWithChars
, startWith
);
990 CFDictionaryAddValue(updatedConstraints
, kSecPasswordGroupSize
, groupSizeRef
);
992 if(numberOfGroupsRef
)
993 CFDictionaryAddValue(updatedConstraints
, kSecPasswordNumberOfGroups
, numberOfGroupsRef
);
996 CFDictionaryAddValue(updatedConstraints
, kSecPasswordSeparator
, separatorRef
);
998 if(atMostCharactersRef
)
999 CFDictionaryAddValue(updatedConstraints
, kSecPasswordContainsNoMoreThanNSpecificCharacters
, atMostCharactersRef
);
1001 if(atLeastCharactersRef
)
1002 CFDictionaryAddValue(updatedConstraints
, kSecPasswordContainsAtLeastNSpecificCharacters
, atLeastCharactersRef
);
1005 CFDictionaryAddValue(updatedConstraints
, kSecPasswordContainsNoMoreThanNConsecutiveIdenticalCharacters
, identicalRef
);
1007 CFReleaseNull(useDefaultPasswordFormat
);
1008 CFReleaseNull(numReqChars
);
1009 CFReleaseNull(allowedCharacters
);
1010 CFReleaseNull(requiredCharacterSets
);
1012 return CFDictionaryCreateCopy(kCFAllocatorDefault
, updatedConstraints
);
1015 static bool isDictionaryFormattedProperly(SecPasswordType type
, CFDictionaryRef passwordRequirements
, CFErrorRef
*error
){
1017 CFTypeRef defaults
= NULL
;
1018 CFErrorRef tempError
= NULL
;
1019 if(passwordRequirements
== NULL
){
1023 if( CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordDefaultForType
, &defaults
) ){
1024 if(isString(defaults
) == true && 0 == CFStringCompare(defaults
, CFSTR("true"), 0)){
1028 //only need to check max and min pin length formatting
1029 if(type
== kSecPasswordTypePIN
){
1030 CFTypeRef minTest
= NULL
, maxTest
= NULL
;
1032 CFIndex minPasswordLength
= 0, maxPasswordLength
= 0;
1034 if( CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordDefaultForType
, &defaults
) ){
1035 if(isString(defaults
) == true && 0 == CFStringCompare(defaults
, CFSTR("true"), 0)){
1039 //check if the values exist!
1040 if( CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordMaxLengthKey
, &maxTest
) ){
1041 require_action_quiet(isNull(maxTest
)!= true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("To generate a password, need a max length"), (CFIndex
)errSecBadReq
, NULL
));
1042 require_action_quiet(isNumber(maxTest
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The password's max length must be a CFNumberRef"), (CFIndex
)errSecBadReq
, NULL
));
1045 if (CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordMinLengthKey
, &minTest
) ){
1046 require_action_quiet(isNull(minTest
)!= true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("To generate a password, need a min length"), (CFIndex
)errSecBadReq
, NULL
));
1047 require_action_quiet(isNumber(minTest
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The password's min length must be a CFNumberRef"), (CFIndex
)errSecBadReq
, NULL
));
1049 //check if the values exist!
1051 CFNumberRef max
= (CFNumberRef
)maxTest
;
1052 CFNumberGetValue(max
, kCFNumberSInt64Type
, &valuePtr
);
1053 maxPasswordLength
= (long)valuePtr
;
1056 CFNumberRef min
= (CFNumberRef
)minTest
;
1057 CFNumberGetValue(min
, kCFNumberSInt64Type
, &valuePtr
);
1058 minPasswordLength
= (long)valuePtr
;
1060 //make sure min and max make sense respective to each other and that they aren't less than 4 digits.
1061 require_action_quiet(minPasswordLength
&& maxPasswordLength
&& minPasswordLength
<= maxPasswordLength
, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The password's length parameters make no sense ( is max < min ?)"), (CFIndex
)errSecBadReq
, NULL
));
1062 require_action_quiet((minPasswordLength
&& minPasswordLength
>= 4) || (maxPasswordLength
&& maxPasswordLength
>= 4), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The password's length parameters make no sense ( is max < min ?)"), (CFIndex
)errSecBadReq
, NULL
));
1065 CFTypeRef allowedTest
, maxTest
, minTest
, requiredTest
, prohibitedCharacters
, endWith
, startWith
,
1066 groupSizeRef
, numberOfGroupsRef
, separatorRef
, atMostCharactersRef
,
1067 atLeastCharactersRef
, thresholdRef
, identicalRef
, characters
;
1070 //check if the values exist!
1071 require_action_quiet(CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordAllowedCharactersKey
, &allowedTest
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("Need a string of characters; password must only contain characters in this string"), (CFIndex
)errSecBadReq
, NULL
));
1072 require_action_quiet( CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordMaxLengthKey
, &maxTest
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("To generate a password, need a max length"), (CFIndex
)errSecBadReq
, NULL
));
1073 require_action_quiet( CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordMinLengthKey
, &minTest
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("To generate a password, need a min length"), (CFIndex
)errSecBadReq
, NULL
));
1074 require_action_quiet(CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordRequiredCharactersKey
, &requiredTest
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("Need an array of character sets, password must have at least 1 character from each set"), (CFIndex
)errSecBadReq
, NULL
));
1076 //check if values are null?
1077 require_action_quiet(isNull(allowedTest
) != true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("Need a string of characters; password must only contain characters in this string"), (CFIndex
)errSecBadReq
, NULL
));
1078 require_action_quiet(isNull(maxTest
)!= true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("To generate a password, need a max length"), (CFIndex
)errSecBadReq
, NULL
));
1079 require_action_quiet(isNull(minTest
)!= true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("To generate a password, need a min length"), (CFIndex
)errSecBadReq
, NULL
));
1080 require_action_quiet(isNull(requiredTest
)!= true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("Need an array of character sets, password must have at least 1 character from each set"), (CFIndex
)errSecBadReq
, NULL
));
1082 //check if the values are correct
1083 require_action_quiet(isString(allowedTest
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The password's allowed characters must be a CFStringRef"), (CFIndex
)errSecBadReq
, NULL
));
1084 require_action_quiet(isNumber(maxTest
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The password's max length must be a CFNumberRef"), (CFIndex
)errSecBadReq
, NULL
));
1085 require_action_quiet(isNumber(minTest
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The password's min length must be a CFNumberRef"), (CFIndex
)errSecBadReq
, NULL
));
1086 require_action_quiet(isArray(requiredTest
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The password's required characters must be an array of CFCharacterSetRefs"), (CFIndex
)errSecBadReq
, NULL
));
1088 CFNumberGetValue(minTest
, kCFNumberSInt64Type
, &valuePtr
);
1089 CFIndex minPasswordLength
= (long)valuePtr
;
1090 CFNumberGetValue(maxTest
, kCFNumberSInt64Type
, &valuePtr
);
1091 CFIndex maxPasswordLength
= (long)valuePtr
;
1093 require_action_quiet(minPasswordLength
<= maxPasswordLength
, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The password's length parameters make no sense ( is max < min ?)"), (CFIndex
)errSecBadReq
, NULL
));
1095 require_action_quiet(CFStringGetLength((CFStringRef
)allowedTest
) != 0, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("Need a string of characters; password must only contain characters in this string"), (CFIndex
)errSecBadReq
, NULL
));
1096 require_action_quiet(CFArrayGetCount((CFArrayRef
)requiredTest
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("Need an array of character sets, password must have at least 1 character from each set"), (CFIndex
)errSecBadReq
, NULL
));
1098 if(CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordDisallowedCharacters
, &prohibitedCharacters
)){
1099 require_action_quiet(isNull(prohibitedCharacters
) != true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("Disallowed Characters dictionary parameter is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1100 require_action_quiet(isString(prohibitedCharacters
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("Disallowed Characters dictionary parameter is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1102 if(CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordCantEndWithChars
, &endWith
)){
1103 require_action_quiet(isNull(endWith
) != true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'EndWith' is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1104 require_action_quiet(isString(endWith
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'EndWith' is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1106 if(CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordCantStartWithChars
, &startWith
)){
1107 require_action_quiet(isNull(startWith
) != true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'StartWith' is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1108 require_action_quiet(isString(startWith
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'StartWith' is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1110 if(CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordGroupSize
, &groupSizeRef
)){
1111 require_action_quiet(isNull(groupSizeRef
) != true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'groupsize' is either null or not a number"), (CFIndex
)errSecBadReq
, NULL
));
1112 require_action_quiet(isNumber(groupSizeRef
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'groupsize' is either null or not a number"), (CFIndex
)errSecBadReq
, NULL
));
1114 if(CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordNumberOfGroups
, &numberOfGroupsRef
)){
1115 require_action_quiet(isNull(numberOfGroupsRef
) != true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'number of groupds' is either null or not a number"), (CFIndex
)errSecBadReq
, NULL
));
1116 require_action_quiet(isNumber(numberOfGroupsRef
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'number of groupds' is either null or not a number"), (CFIndex
)errSecBadReq
, NULL
));
1118 if(CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordSeparator
, &separatorRef
)){
1119 require_action_quiet(isNull(separatorRef
) != true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'password separator character' is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1120 require_action_quiet(isString(separatorRef
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'password separator character' is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1123 if(CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordContainsNoMoreThanNSpecificCharacters
, &atMostCharactersRef
)){
1124 require_action_quiet(isNull(atMostCharactersRef
) != true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'At Most N Characters' is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1125 require_action_quiet(isDictionary(atMostCharactersRef
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'At Most N Characters' is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1127 require_action_quiet(CFDictionaryGetValueIfPresent(atMostCharactersRef
, kSecPasswordCharacterCount
, &thresholdRef
) != false, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'At Most N Characters' is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1128 require_action_quiet(isNull(thresholdRef
) != true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'characters' is either null or not a number"), (CFIndex
)errSecBadReq
, NULL
));
1129 require_action_quiet(isNumber(thresholdRef
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'characters' is either null or not a number"), (CFIndex
)errSecBadReq
, NULL
));
1131 require_action_quiet(CFDictionaryGetValueIfPresent(atMostCharactersRef
, kSecPasswordCharacters
, &characters
)!= false, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'At Most N Characters' is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1132 require_action_quiet(isNull(characters
) != true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'Characters' is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1133 require_action_quiet(isString(characters
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'Characters' is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1136 if(CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordContainsAtLeastNSpecificCharacters
, &atLeastCharactersRef
)){
1137 require_action_quiet(isNull(atLeastCharactersRef
) != true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'At Least N Characters' is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1138 require_action_quiet(isDictionary(atLeastCharactersRef
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'At Least N Characters' is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1140 require_action_quiet(CFDictionaryGetValueIfPresent(atLeastCharactersRef
, kSecPasswordCharacterCount
, &thresholdRef
) != false, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'At Least N Characters' is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1142 require_action_quiet(isNull(thresholdRef
) != true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'characters' is either null or not a number"), (CFIndex
)errSecBadReq
, NULL
));
1143 require_action_quiet(isNumber(thresholdRef
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'characters' is either null or not a number"), (CFIndex
)errSecBadReq
, NULL
));
1145 require_action_quiet(CFDictionaryGetValueIfPresent(atLeastCharactersRef
, kSecPasswordCharacters
, &characters
) != false, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'At Least N Characters' is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1146 require_action_quiet(isNull(characters
) != true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'Characters' is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1147 require_action_quiet(isString(characters
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'Characters' is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1150 if(CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordContainsNoMoreThanNConsecutiveIdenticalCharacters
, &identicalRef
)){
1151 require_action_quiet(isNull(identicalRef
) != true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'Identical Consecutive Characters' is either null or not a number"), (CFIndex
)errSecBadReq
, NULL
));
1152 require_action_quiet(isNumber(identicalRef
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'Identical Consecutive Characters' is either null or not a number"), (CFIndex
)errSecBadReq
, NULL
));
1159 if (tempError
!= NULL
) {
1161 *error
= CFRetainSafe(tempError
);
1165 CFReleaseNull(tempError
);
1170 static bool doesFinalPasswordPass(bool isSimple
, CFStringRef password
, CFDictionaryRef requirements
){
1172 CFTypeRef characters
, identicalRef
= NULL
, NRef
= NULL
, endWith
= NULL
, startWith
= NULL
, atLeastCharacters
= NULL
, atMostCharacters
= NULL
;
1174 CFIndex N
, identicalCount
;
1175 CFArrayRef requiredCharacterSet
= (CFArrayRef
)CFDictionaryGetValue(requirements
, kSecRequiredCharacterSetsKey
);
1177 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordCantEndWithChars
, &endWith
))
1180 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordCantStartWithChars
, &startWith
))
1183 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordContainsAtLeastNSpecificCharacters
, &atLeastCharacters
))
1184 atLeastCharacters
= NULL
;
1186 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordContainsNoMoreThanNSpecificCharacters
, &atMostCharacters
))
1187 atMostCharacters
= NULL
;
1189 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordContainsNoMoreThanNConsecutiveIdenticalCharacters
, &identicalRef
))
1190 identicalRef
= NULL
;
1192 CFNumberGetValue((CFNumberRef
)identicalRef
, kCFNumberSInt64Type
, &valuePtr
);
1193 identicalCount
= (long)valuePtr
;
1197 if(!doesPasswordEndWith(password
, endWith
))
1200 if(startWith
!= NULL
){
1201 if(!doesPasswordStartWith(password
, startWith
))
1204 if(atLeastCharacters
!= NULL
){
1205 NRef
= CFDictionaryGetValue(atLeastCharacters
, kSecPasswordCharacterCount
);
1206 characters
= CFDictionaryGetValue(atLeastCharacters
, kSecPasswordCharacters
);
1207 CFNumberGetValue((CFNumberRef
)NRef
, kCFNumberSInt64Type
, &valuePtr
);
1209 if(!passwordContainsAtLeastNCharacters(password
, characters
, N
))
1212 if(atMostCharacters
!= NULL
){
1213 NRef
= CFDictionaryGetValue(atMostCharacters
, kSecPasswordCharacterCount
);
1214 characters
= CFDictionaryGetValue(atMostCharacters
, kSecPasswordCharacters
);
1215 CFNumberGetValue((CFNumberRef
)NRef
, kCFNumberSInt64Type
, &valuePtr
);
1217 if(!passwordContainsLessThanNCharacters(password
, characters
, N
))
1220 if(identicalRef
!= NULL
){
1221 if(!passwordContainsLessThanNIdenticalCharacters(password
, identicalCount
))
1224 if (!passwordContainsRequiredCharacters(password
, requiredCharacterSet
))
1227 if(true == SecPasswordIsPasswordWeak2(isSimple
, password
))
1233 //entry point into password generation
1234 CF_RETURNS_RETAINED CFStringRef
SecPasswordGenerate(SecPasswordType type
, CFErrorRef
*error
, CFDictionaryRef passwordRequirements
){
1235 bool check
= false, isSimple
= false;
1236 CFTypeRef separator
= NULL
, defaults
= NULL
, groupSizeRef
= NULL
, numberOfGroupsRef
= NULL
;
1237 CFDictionaryRef properlyFormattedRequirements
= NULL
;
1238 CFErrorRef localError
= NULL
;
1239 uint64_t valuePtr
, groupSize
, numberOfGroups
;
1240 CFNumberRef numberOfRequiredRandomCharacters
;
1241 CFIndex requiredCharactersSize
;
1242 CFStringRef randomCharacters
= NULL
, password
= NULL
, allowedChars
= NULL
;
1243 CFMutableStringRef finalPassword
= NULL
;
1245 if(type
== kSecPasswordTypePIN
)
1249 check
= isDictionaryFormattedProperly(type
, passwordRequirements
, &localError
);
1250 require_quiet(check
!= false, fail
);
1252 //should we generate defaults?
1253 if(passwordRequirements
== NULL
|| (CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordDefaultForType
, &defaults
) && isString(defaults
) == true && 0 == CFStringCompare(defaults
, CFSTR("true"), 0) ))
1254 properlyFormattedRequirements
= passwordGenerateCreateDefaultParametersDictionary(type
, passwordRequirements
);
1256 properlyFormattedRequirements
= passwordGenerationCreateParametersDictionary(type
, passwordRequirements
);
1258 require_quiet(localError
== NULL
&& properlyFormattedRequirements
!= NULL
, fail
);
1260 numberOfRequiredRandomCharacters
= (CFNumberRef
)CFDictionaryGetValue(properlyFormattedRequirements
, kSecNumberOfRequiredRandomCharactersKey
);
1261 CFNumberGetValue(numberOfRequiredRandomCharacters
, kCFNumberSInt64Type
, &valuePtr
);
1262 requiredCharactersSize
= (long)valuePtr
;
1264 if(!CFDictionaryGetValueIfPresent(properlyFormattedRequirements
, kSecPasswordGroupSize
, &groupSizeRef
)){
1265 groupSizeRef
= NULL
;
1268 CFNumberGetValue((CFNumberRef
)groupSizeRef
, kCFNumberSInt64Type
, &groupSize
);
1270 if(!CFDictionaryGetValueIfPresent(properlyFormattedRequirements
, kSecPasswordNumberOfGroups
, &numberOfGroupsRef
)){
1271 numberOfGroupsRef
= NULL
;
1274 CFNumberGetValue((CFNumberRef
)numberOfGroupsRef
, kCFNumberSInt64Type
, &numberOfGroups
);
1277 allowedChars
= CFDictionaryGetValue(properlyFormattedRequirements
, kSecAllowedCharactersKey
);
1278 getPasswordRandomCharacters(&randomCharacters
, properlyFormattedRequirements
, &requiredCharactersSize
, allowedChars
);
1280 if(numberOfGroupsRef
&& groupSizeRef
){
1281 finalPassword
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
1283 if(!CFDictionaryGetValueIfPresent(properlyFormattedRequirements
, kSecPasswordSeparator
, &separator
))
1286 if(separator
== NULL
)
1287 separator
= CFSTR("-");
1290 while( i
!= requiredCharactersSize
){
1291 if((i
+ (CFIndex
)groupSize
) < requiredCharactersSize
){
1292 CFStringAppend(finalPassword
, CFStringCreateWithSubstring(kCFAllocatorDefault
, randomCharacters
, CFRangeMake(i
, (CFIndex
)groupSize
)));
1293 CFStringAppend(finalPassword
, separator
);
1296 else if((i
+(CFIndex
)groupSize
) == requiredCharactersSize
){
1297 CFStringAppend(finalPassword
, CFStringCreateWithSubstring(kCFAllocatorDefault
, randomCharacters
, CFRangeMake(i
, (CFIndex
)groupSize
)));
1301 CFStringAppend(finalPassword
, CFStringCreateWithSubstring(kCFAllocatorDefault
, randomCharacters
, CFRangeMake(i
, requiredCharactersSize
- i
)));
1302 i
+=(requiredCharactersSize
- i
);
1305 password
= CFStringCreateCopy(kCFAllocatorDefault
, finalPassword
);
1306 CFReleaseNull(finalPassword
);
1308 //no fancy formatting
1310 password
= CFStringCreateCopy(kCFAllocatorDefault
, randomCharacters
);
1313 CFReleaseNull(randomCharacters
);
1314 require_quiet(doesFinalPasswordPass(isSimple
, password
, properlyFormattedRequirements
), no_pass
);
1315 CFReleaseNull(properlyFormattedRequirements
);
1319 CFReleaseNull(password
);
1323 if (error
&& localError
) {
1324 *error
= localError
;
1328 CFReleaseSafe(localError
);
1329 CFReleaseNull(properlyFormattedRequirements
);
1333 const char *in_word_set (const char *str
, unsigned int len
){
1334 static const char * wordlist
[] =
1336 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
1337 "", "", "0103", "", "", "", "", "0123", "", "", "", "", "0303", "", "", "",
1338 "", "", "", "", "0110", "", "1103", "", "", "", "", "1123", "", "", "0000",
1339 "", "1203", "", "0404", "", "", "", "", "1234", "1110", "2015", "2013", "",
1340 "2014", "1010", "2005", "2003", "", "2004", "1210", "0505", "0111", "", "",
1341 "", "2008", "0101", "", "2007", "", "", "", "", "2006", "2010", "1995", "1993",
1342 "", "1994", "2000", "", "1111", "", "", "", "1998", "1101", "", "1997", "",
1343 "0808", "1211", "", "1996", "0102", "", "1201", "", "", "1990", "", "", "",
1344 "", "0202", "", "2011", "", "", "1112", "1958", "2001", "", "1957", "1102",
1345 "", "3333", "", "1956", "1212", "1985", "1983", "", "1984", "1202", "", "0909",
1346 "", "0606", "", "1988", "1991", "", "1987", "2012", "", "", "", "1986", "2002",
1347 "", "", "", "0707", "1980", "", "2009", "", "", "2222", "1965", "1963", "",
1348 "1964", "", "", "2229", "", "", "1992", "1968", "", "", "1967", "", "", "1999",
1349 "", "1966", "", "1975", "1973", "", "1974", "1960", "", "1981", "", "4444",
1350 "", "1978", "", "7465", "1977", "", "", "", "", "1976", "2580", "", "1959",
1351 "", "", "1970", "", "", "", "", "", "", "", "", "", "1982", "", "1961", "",
1352 "", "5252", "", "1989", "", "", "", "", "", "", "", "", "", "", "", "", "",
1353 "", "1971", "", "", "", "", "", "", "", "1962", "", "5683", "", "6666", "",
1354 "", "1969", "", "", "", "", "", "", "", "", "", "", "", "", "1972", "", "",
1355 "", "", "", "", "1979", "", "", "", "7667"
1358 if (len
<= MAX_WORD_LENGTH
&& len
>= MIN_WORD_LENGTH
)
1360 register int key
= pinhash (str
, len
);
1362 if (key
<= MAX_HASH_VALUE
&& key
>= 0)
1364 register const char *s
= wordlist
[key
];
1365 if (*str
== *s
&& !strcmp (str
+ 1, s
+ 1))
1371 CFDictionaryRef
SecPasswordCopyDefaultPasswordLength(SecPasswordType type
, CFErrorRef
*error
){
1373 CFIndex tupleLengthInt
= 0, numOfTuplesInt
= 0;
1374 CFNumberRef tupleLength
= NULL
;
1375 CFNumberRef numOfTuples
= NULL
;
1377 CFMutableDictionaryRef passwordLengthDefaults
= NULL
;
1378 CFDictionaryRef result
= NULL
;
1381 case(kSecPasswordTypeiCloudRecovery
):
1386 case(kSecPasswordTypePIN
):
1391 case(kSecPasswordTypeSafari
):
1396 case(kSecPasswordTypeWifi
):
1402 if(SecError(errSecBadReq
, error
, CFSTR("Password type does not exist.")) == false)
1404 secdebug("secpasswordcopydefaultpasswordlength", "could not create error!");
1408 if (tupleLengthInt
!= 0 && numOfTuplesInt
!= 0) {
1409 tupleLength
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberCFIndexType
, &tupleLengthInt
);
1410 numOfTuples
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberCFIndexType
, &numOfTuplesInt
);
1411 passwordLengthDefaults
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
1412 CFDictionaryAddValue(passwordLengthDefaults
, kSecPasswordGroupSize
, tupleLength
);
1413 CFDictionaryAddValue(passwordLengthDefaults
, kSecPasswordNumberOfGroups
, numOfTuples
);
1414 result
= CFDictionaryCreateCopy(kCFAllocatorDefault
, passwordLengthDefaults
);
1417 CFReleaseSafe(tupleLength
);
1418 CFReleaseSafe(numOfTuples
);
1419 CFReleaseSafe(passwordLengthDefaults
);