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
252 //check if PIN is a bunch of incrementing numbers
253 for(int i
= 0; i
< CFStringGetLength(passcode
); i
++){
254 if(i
== CFStringGetLength(passcode
)-1){
258 else if ((pin
[i
] + 1) == pin
[i
+1])
263 //check if PIN is a bunch of decrementing numbers
264 for(int i
= 0; i
< CFStringGetLength(passcode
); i
++){
265 if(i
== CFStringGetLength(passcode
)-1){
269 else if ((pin
[i
]) == (pin
[i
+1] +1))
271 else if ((i
== 0) && (pin
[i
] == '0') && (pin
[i
+1] == '9'))
278 for(CFIndex i
= 0; i
< blacklistLength
; i
++)
280 const char* blackCode
= blacklist
[i
];
281 if(0 == strcmp(blackCode
, pin
))
284 return true; //weak password
288 else if(isNumber
){ //dealing with a numeric PIN
289 pin
= CFStringToCString(passcode
);
290 //check if PIN is all the same number
291 for(int i
= 0; i
< CFStringGetLength(passcode
); i
++){
292 if(i
+1 >= CFStringGetLength(passcode
)){
296 else if (pin
[i
] == pin
[i
+1])
301 //check if PIN is a bunch of incrementing numbers
302 for(int i
= 0; i
< CFStringGetLength(passcode
); i
++){
303 if(i
== CFStringGetLength(passcode
)-1){
307 else if ((pin
[i
] + 1) == pin
[i
+1])
312 //check if PIN is a bunch of decrementing numbers
313 for(int i
= 0; i
< CFStringGetLength(passcode
); i
++){
314 if(i
== CFStringGetLength(passcode
)-1){
318 else if ((pin
[i
]) == (pin
[i
+1] +1))
320 else if ((i
== 0) && (pin
[i
] == '0') && (pin
[i
+1] == '9'))
326 else{ // password is complex, evaluate entropy
331 int characterSet
= 0;
333 //calculate new entropy
334 for(CFIndex i
= 0; i
< CFStringGetLength(passcode
); i
++){
336 if( CFStringFindCharacterFromSet(passcode
, uppercaseLetterCharacterSet
, CFRangeMake(i
,1), kCFCompareBackwards
, NULL
)){
340 if( CFStringFindCharacterFromSet(passcode
, lowercaseLetterCharacterSet
, CFRangeMake(i
,1), kCFCompareBackwards
, NULL
)){
344 if( CFStringFindCharacterFromSet(passcode
, decimalDigitCharacterSet
, CFRangeMake(i
,1), kCFCompareBackwards
, NULL
)){
348 if( CFStringFindCharacterFromSet(passcode
, punctuationCharacterSet
, CFRangeMake(i
,1), kCFCompareBackwards
, NULL
)){
355 characterSet
+= alphabetSetSize
;
358 characterSet
+= alphabetSetSize
;
361 characterSet
+= decimalSetSize
;
364 characterSet
+= punctuationSetSize
;
367 double strength
= CFStringGetLength(passcode
)*log2(characterSet
);
369 if(strength
< entropyStrengthThreshold
){
373 return false; //strong
378 return false; //strong password
382 static bool SecPasswordIsPasscodeIncrementingOrDecrementingDigits(CFStringRef passcode
)
384 char* pin
= CFStringToCString(passcode
);
386 //check if PIN is a bunch of incrementing numbers
387 for(int i
= 0; i
< CFStringGetLength(passcode
); i
++){
388 if(i
== CFStringGetLength(passcode
)-1){
392 else if ((pin
[i
] + 1) == pin
[i
+1])
397 //check if PIN is a bunch of decrementing numbers
398 for(int i
= 0; i
< CFStringGetLength(passcode
); i
++){
399 if(i
== CFStringGetLength(passcode
)-1){
403 else if ((pin
[i
]) == (pin
[i
+1] +1))
405 else if ((i
== 0) && (pin
[i
] == '0') && (pin
[i
+1] == '9'))
414 static bool SecPasswordIsPasswordRepeatingTwoNumbers(CFStringRef passcode
){
415 char* pin
= CFStringToCString(passcode
);
417 for(int i
= 0; i
< CFStringGetLength(passcode
); i
++)
419 if(i
+2 == CFStringGetLength(passcode
)-1){
423 else if(pin
[i
] == pin
[i
+2])
433 bool SecPasswordIsPasswordWeak2(bool isSimple
, CFStringRef passcode
)
435 uppercaseLetterCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetUppercaseLetter
);
436 lowercaseLetterCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetLowercaseLetter
);
437 decimalDigitCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
);
438 punctuationCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetPunctuation
);
444 if( CFStringGetLength(passcode
) < 4 ){
445 return true; //weak password
448 bool isPasscodeNumber
= true;
449 //check to see if passcode is a number
450 for(CFIndex i
= 0; i
< CFStringGetLength(passcode
); i
++){
451 if( CFStringFindCharacterFromSet(passcode
, decimalDigitCharacterSet
, CFRangeMake(i
,1), 0, NULL
))
454 isPasscodeNumber
= false;
460 //checking to see if it's a 4 digit pin
461 if(isPasscodeNumber
&& CFStringGetLength(passcode
) == 4){
463 pin
= CFStringToCString(passcode
);
464 if(in_word_set(pin
, 4)){
469 CFIndex blacklistLength
= (CFIndex
)sizeof(blacklist
)/sizeof(blacklist
[0]);
471 //not all the same number
472 if(pin
[0] == pin
[1] == pin
[2] == pin
[3]){
474 return true; //weak password
476 //first two digits being the same and the last two digits being the same
477 if ( pin
[0] == pin
[1] && pin
[2] == pin
[3]){
479 return true; //weak password
481 //first two digits not being the same as the last two digits
482 if(pin
[0] == pin
[2] && pin
[1] == pin
[3]){
484 return true; //weak password
487 for(CFIndex i
= 0; i
< blacklistLength
; i
++)
489 const char* blackCode
= blacklist
[i
];
490 if(0 == strcmp(blackCode
, pin
))
493 return true; //weak password
497 else if(isPasscodeNumber
&& CFStringGetLength(passcode
) == 6){
498 pin
= CFStringToCString(passcode
);
500 //not all the same number
501 for(int i
= 0; i
< CFStringGetLength(passcode
); i
++){
502 if(i
== CFStringGetLength(passcode
)-1){
506 else if ((pin
[i
]) == pin
[i
+1])
511 //passcode is incrementing ex 123456 or 654321
512 if(SecPasswordIsPasscodeIncrementingOrDecrementingDigits(passcode
)) {
516 //passcode does not consist of 2 repeating digits
517 if(SecPasswordIsPasswordRepeatingTwoNumbers(passcode
)){
522 else//should be a 4 or 6digit number
525 else if(isPasscodeNumber
&& !isSimple
){ //dealing with a complex numeric passcode
526 pin
= CFStringToCString(passcode
);
527 //check if PIN is all the same number
528 for(int i
= 0; i
< CFStringGetLength(passcode
); i
++){
529 if(i
+1 >= CFStringGetLength(passcode
)){
533 else if (pin
[i
] == pin
[i
+1])
538 if(SecPasswordIsPasscodeIncrementingOrDecrementingDigits(passcode
)) {
542 if(SecPasswordIsPasswordRepeatingTwoNumbers(passcode
)){
548 else{ // password is complex, evaluate entropy
553 int characterSet
= 0;
555 //calculate new entropy
556 for(CFIndex i
= 0; i
< CFStringGetLength(passcode
); i
++){
558 if( CFStringFindCharacterFromSet(passcode
, uppercaseLetterCharacterSet
, CFRangeMake(i
,1), kCFCompareBackwards
, NULL
)){
562 if( CFStringFindCharacterFromSet(passcode
, lowercaseLetterCharacterSet
, CFRangeMake(i
,1), kCFCompareBackwards
, NULL
)){
566 if( CFStringFindCharacterFromSet(passcode
, decimalDigitCharacterSet
, CFRangeMake(i
,1), kCFCompareBackwards
, NULL
)){
570 if( CFStringFindCharacterFromSet(passcode
, punctuationCharacterSet
, CFRangeMake(i
,1), kCFCompareBackwards
, NULL
)){
577 characterSet
+= alphabetSetSize
;
580 characterSet
+= alphabetSetSize
;
583 characterSet
+= decimalSetSize
;
586 characterSet
+= punctuationSetSize
;
589 double strength
= CFStringGetLength(passcode
)*log2(characterSet
);
591 if(strength
< entropyStrengthThreshold
){
595 return false; //strong
600 return false; //strong password
604 static void getUniformRandomNumbers(uint8_t* buffer
, size_t numberOfDesiredNumbers
, uint8_t upperBound
)
607 // The values returned by SecRandomCopyBytes are uniformly distributed in the range [0, 255]. If we try to map
608 // these values onto a smaller range using modulo we will introduce a bias towards lower numbers in situations
609 // where our smaller range doesn’t evenly divide in to [0, 255]. For example, with the desired range of [0, 54]
610 // the ranges 0..54, 55..109, 110..164, and 165..219 are uniformly distributed, but the range 220..255 modulo 55
611 // is only distributed over [0, 35], giving significant bias to these lower values. So, we ignore random numbers
612 // that would introduce this bias.
613 uint8_t limitAvoidingModuloBias
= UCHAR_MAX
- (UCHAR_MAX
% upperBound
);
615 for (size_t numberOfAcceptedNumbers
= 0; numberOfAcceptedNumbers
< numberOfDesiredNumbers
; ) {
616 if (SecRandomCopyBytes(kSecRandomDefault
, numberOfDesiredNumbers
- numberOfAcceptedNumbers
, buffer
+ numberOfAcceptedNumbers
) == -1)
618 for (size_t i
= numberOfAcceptedNumbers
; i
< numberOfDesiredNumbers
; ++i
) {
619 if (buffer
[i
] < limitAvoidingModuloBias
)
620 buffer
[numberOfAcceptedNumbers
++] = buffer
[i
] % upperBound
;
625 static bool passwordContainsRequiredCharacters(CFStringRef password
, CFArrayRef requiredCharacterSets
)
627 CFCharacterSetRef characterSet
;
629 for (CFIndex i
= 0; i
< CFArrayGetCount(requiredCharacterSets
); i
++) {
630 characterSet
= CFArrayGetValueAtIndex(requiredCharacterSets
, i
);
631 CFRange rangeToSearch
= CFRangeMake(0, CFStringGetLength(password
));
632 require_quiet(CFStringFindCharacterFromSet(password
, characterSet
, rangeToSearch
, 0, NULL
), fail
);
641 static bool passwordContainsLessThanNIdenticalCharacters(CFStringRef password
, CFIndex identicalCount
)
643 unsigned char Char
, nextChar
;
646 for(CFIndex i
= 0; i
< CFStringGetLength(password
); i
++){
647 Char
= CFStringGetCharacterAtIndex(password
, i
);
648 for(CFIndex j
= i
; j
< CFStringGetLength(password
); j
++){
649 nextChar
= CFStringGetCharacterAtIndex(password
, j
);
650 require_quiet(repeating
<= identicalCount
, fail
);
651 if(Char
== nextChar
){
664 static bool passwordContainsAtLeastNCharacters(CFStringRef password
, CFStringRef characters
, CFIndex N
)
666 CFCharacterSetRef characterSet
= NULL
;
667 characterSet
= CFCharacterSetCreateWithCharactersInString(kCFAllocatorDefault
, characters
);
670 for(CFIndex i
= 0; i
< CFStringGetLength(password
); i
++){
671 if(CFStringFindCharacterFromSet(password
, characterSet
, CFRangeMake(i
, 1), 0, NULL
))
674 CFReleaseNull(characterSet
);
681 static bool passwordContainsLessThanNCharacters(CFStringRef password
, CFStringRef characters
, CFIndex N
)
683 CFCharacterSetRef characterSet
= NULL
;
684 characterSet
= CFCharacterSetCreateWithCharactersInString(kCFAllocatorDefault
, characters
);
687 for(CFIndex i
= 0; i
< CFStringGetLength(password
); i
++){
688 if(CFStringFindCharacterFromSet(password
, characterSet
, CFRangeMake(i
, 1), 0, NULL
))
691 CFReleaseNull(characterSet
);
698 static bool passwordDoesNotContainCharacters(CFStringRef password
, CFStringRef prohibitedCharacters
)
700 CFCharacterSetRef characterSet
= NULL
;
701 characterSet
= CFCharacterSetCreateWithCharactersInString(kCFAllocatorDefault
, prohibitedCharacters
);
702 CFRange rangeToSearch
= CFRangeMake(0, CFStringGetLength(password
));
704 require_quiet(!CFStringFindCharacterFromSet(password
, characterSet
, rangeToSearch
, 0, NULL
), fail
);
705 CFReleaseNull(characterSet
);
708 CFReleaseNull(characterSet
);
712 static void getPasswordRandomCharacters(CFStringRef
*returned
, CFDictionaryRef requirements
, CFIndex
*numberOfRandomCharacters
, CFStringRef allowedCharacters
)
714 uint8_t randomNumbers
[*numberOfRandomCharacters
];
715 unsigned char randomCharacters
[*numberOfRandomCharacters
];
716 getUniformRandomNumbers(randomNumbers
, *numberOfRandomCharacters
, CFStringGetLength(allowedCharacters
));
718 CFTypeRef prohibitedCharacters
= NULL
;
719 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordDisallowedCharacters
, &prohibitedCharacters
))
720 prohibitedCharacters
= NULL
;
722 //it's faster for long characters to check each character produced for these cases
723 for (CFIndex i
= 0; i
< *numberOfRandomCharacters
; ++i
){
724 //check prohibited characters
725 UniChar randomChar
[1];
726 randomChar
[0] = CFStringGetCharacterAtIndex(allowedCharacters
, randomNumbers
[i
]);
727 if (prohibitedCharacters
!= NULL
)
729 CFStringRef temp
= CFStringCreateWithCharacters(kCFAllocatorDefault
, randomChar
, 1);
730 bool pwdncc
= passwordDoesNotContainCharacters(temp
, prohibitedCharacters
);
733 //change up the random numbers so we don't get the same index into allowed
734 getUniformRandomNumbers(randomNumbers
, *numberOfRandomCharacters
, CFStringGetLength(allowedCharacters
));
739 randomCharacters
[i
] = (unsigned char)randomChar
[0];
742 *returned
= CFStringCreateWithBytes(kCFAllocatorDefault
, randomCharacters
, *numberOfRandomCharacters
, kCFStringEncodingUTF8
, false);
745 static bool doesPasswordEndWith(CFStringRef password
, CFStringRef prohibitedCharacters
)
747 CFCharacterSetRef characterSet
= NULL
;
748 characterSet
= CFCharacterSetCreateWithCharactersInString(kCFAllocatorDefault
, prohibitedCharacters
);
750 CFRange rangeToSearch
= CFRangeMake(CFStringGetLength(password
) - CFStringGetLength(prohibitedCharacters
), CFStringGetLength(prohibitedCharacters
));
751 require_quiet(0 == CFStringCompareWithOptions(password
, prohibitedCharacters
, rangeToSearch
, 0), fail
);
752 CFReleaseNull(characterSet
);
755 CFReleaseNull(characterSet
);
759 static bool doesPasswordStartWith(CFStringRef password
, CFStringRef prohibitedCharacters
)
761 CFCharacterSetRef characterSet
= NULL
;
762 characterSet
= CFCharacterSetCreateWithCharactersInString(kCFAllocatorDefault
, prohibitedCharacters
);
764 CFRange rangeToSearch
= CFRangeMake(0, CFStringGetLength(prohibitedCharacters
));
765 require_quiet(0 == CFStringCompareWithOptions(password
, prohibitedCharacters
, rangeToSearch
, 0), fail
);
766 CFReleaseNull(characterSet
);
767 return false; //does not start with prohibitedCharacters
769 CFReleaseNull(characterSet
);
773 static CFDictionaryRef
passwordGenerateCreateDefaultParametersDictionary(SecPasswordType type
, CFDictionaryRef requirements
){
775 CFMutableArrayRef requiredCharacterSets
= NULL
;
776 CFNumberRef numReqChars
= NULL
;
777 CFStringRef defaultPasswordFormat
= NULL
;
778 requiredCharacterSets
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
779 defaultPasswordFormat
= CFSTR("true");
780 CFTypeRef groupSizeRef
= NULL
, numberOfGroupsRef
= NULL
;
781 CFIndex groupSize
, numberOfGroups
;
782 CFDictionaryRef returned
= NULL
;
785 case(kSecPasswordTypeiCloudRecovery
):
786 numReqChars
= CFNumberCreateWithCFIndex(kCFAllocatorDefault
, defaultiCloudPasswordLength
);
789 groupSizeRef
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &groupSize
);
790 numberOfGroupsRef
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &numberOfGroups
);
792 uppercaseLetterCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetUppercaseLetter
);
793 decimalDigitCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
);
794 CFArrayAppendValue(requiredCharacterSets
, uppercaseLetterCharacterSet
);
795 CFArrayAppendValue(requiredCharacterSets
, decimalDigitCharacterSet
);
796 returned
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
797 kSecUseDefaultPasswordFormatKey
, defaultPasswordFormat
,
798 kSecNumberOfRequiredRandomCharactersKey
, numReqChars
,
799 kSecAllowedCharactersKey
, defaultiCloudCharacters
,
800 kSecRequiredCharacterSetsKey
, requiredCharacterSets
,
801 kSecPasswordGroupSize
, groupSizeRef
,
802 kSecPasswordNumberOfGroups
, numberOfGroupsRef
,
806 case(kSecPasswordTypePIN
):
807 numReqChars
= CFNumberCreateWithCFIndex(kCFAllocatorDefault
, defaultPINLength
);
810 groupSizeRef
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &groupSize
);
811 numberOfGroupsRef
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &numberOfGroups
);
813 decimalDigitCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
);
814 CFArrayAppendValue(requiredCharacterSets
, decimalDigitCharacterSet
);
815 returned
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
816 kSecUseDefaultPasswordFormatKey
, defaultPasswordFormat
,
817 kSecNumberOfRequiredRandomCharactersKey
, numReqChars
,
818 kSecAllowedCharactersKey
, defaultPINCharacters
,
819 kSecRequiredCharacterSetsKey
, requiredCharacterSets
,
820 kSecPasswordGroupSize
, groupSizeRef
,
821 kSecPasswordNumberOfGroups
, numberOfGroupsRef
,
825 case(kSecPasswordTypeWifi
):
828 groupSizeRef
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &groupSize
);
829 numberOfGroupsRef
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &numberOfGroups
);
831 lowercaseLetterCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetLowercaseLetter
);
832 decimalDigitCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
);
834 numReqChars
= CFNumberCreateWithCFIndex(kCFAllocatorDefault
, defaultWifiPasswordLength
);
835 CFArrayAppendValue(requiredCharacterSets
, lowercaseLetterCharacterSet
);
836 CFArrayAppendValue(requiredCharacterSets
, decimalDigitCharacterSet
);
837 returned
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
838 kSecUseDefaultPasswordFormatKey
, defaultPasswordFormat
,
839 kSecNumberOfRequiredRandomCharactersKey
, numReqChars
,
840 kSecAllowedCharactersKey
, defaultWifiCharacters
,
841 kSecRequiredCharacterSetsKey
, requiredCharacterSets
,
842 kSecPasswordGroupSize
, groupSizeRef
,
843 kSecPasswordNumberOfGroups
, numberOfGroupsRef
,
850 groupSizeRef
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &groupSize
);
851 numberOfGroupsRef
= CFNumberCreate(NULL
, kCFNumberCFIndexType
, &numberOfGroups
);
852 uppercaseLetterCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetUppercaseLetter
);
853 lowercaseLetterCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetLowercaseLetter
);
854 decimalDigitCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
);
855 CFArrayAppendValue(requiredCharacterSets
, uppercaseLetterCharacterSet
);
856 CFArrayAppendValue(requiredCharacterSets
, lowercaseLetterCharacterSet
);
857 CFArrayAppendValue(requiredCharacterSets
, decimalDigitCharacterSet
);
859 numReqChars
= CFNumberCreateWithCFIndex(kCFAllocatorDefault
, defaultNumberOfRandomCharacters
);
860 returned
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
861 kSecUseDefaultPasswordFormatKey
, defaultPasswordFormat
,
862 kSecNumberOfRequiredRandomCharactersKey
, numReqChars
,
863 kSecAllowedCharactersKey
, defaultCharacters
,
864 kSecRequiredCharacterSetsKey
, requiredCharacterSets
,
865 kSecPasswordGroupSize
, groupSizeRef
,
866 kSecPasswordNumberOfGroups
, numberOfGroupsRef
,
874 CFReleaseNull(numReqChars
);
875 CFReleaseNull(requiredCharacterSets
);
876 CFReleaseNull(groupSizeRef
);
877 CFReleaseNull(numberOfGroupsRef
);
880 static CFDictionaryRef
passwordGenerationCreateParametersDictionary(SecPasswordType type
, CFDictionaryRef requirements
)
882 CFMutableArrayRef requiredCharacterSets
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
883 CFNumberRef numReqChars
= NULL
;
884 CFIndex numberOfRequiredRandomCharacters
;
885 CFStringRef allowedCharacters
= NULL
, useDefaultPasswordFormat
= NULL
;
887 CFTypeRef prohibitedCharacters
= NULL
, endWith
= NULL
, startWith
= NULL
,
888 groupSizeRef
= NULL
, numberOfGroupsRef
= NULL
, separatorRef
= NULL
,
889 atMostCharactersRef
= NULL
,atLeastCharactersRef
= NULL
, identicalRef
= NULL
;
891 CFNumberRef min
= (CFNumberRef
)CFDictionaryGetValue(requirements
, kSecPasswordMinLengthKey
);
892 CFNumberRef max
= (CFNumberRef
)CFDictionaryGetValue(requirements
, kSecPasswordMaxLengthKey
);
894 CFNumberGetValue(min
, kCFNumberSInt64Type
, &valuePtr
);
895 CFIndex minPasswordLength
= (long)valuePtr
;
896 CFNumberGetValue(max
, kCFNumberSInt64Type
, &valuePtr
);
897 CFIndex maxPasswordLength
= (long)valuePtr
;
899 // If requirements allow, we will generate the password in default format.
900 useDefaultPasswordFormat
= CFSTR("true");
901 numberOfRequiredRandomCharacters
= defaultNumberOfRandomCharacters
;
903 if(type
== kSecPasswordTypePIN
)
905 if( maxPasswordLength
&& minPasswordLength
)
906 numberOfRequiredRandomCharacters
= maxPasswordLength
;
907 else if( !maxPasswordLength
&& minPasswordLength
)
908 numberOfRequiredRandomCharacters
= minPasswordLength
;
909 else if( !minPasswordLength
&& maxPasswordLength
)
910 numberOfRequiredRandomCharacters
= maxPasswordLength
;
912 numberOfRequiredRandomCharacters
= defaultPINLength
;
914 allowedCharacters
= CFSTR("0123456789");
915 CFArrayAppendValue(requiredCharacterSets
, decimalDigitCharacterSet
);
916 useDefaultPasswordFormat
= CFSTR("false");
919 CFArrayRef requiredCharactersArray
= NULL
;
921 if (minPasswordLength
&& minPasswordLength
> defaultNumberOfRandomCharacters
) {
922 useDefaultPasswordFormat
= CFSTR("false");
923 numberOfRequiredRandomCharacters
= minPasswordLength
;
925 if (maxPasswordLength
&& maxPasswordLength
< defaultNumberOfRandomCharacters
) {
926 useDefaultPasswordFormat
= CFSTR("false");
927 numberOfRequiredRandomCharacters
= maxPasswordLength
;
929 if (maxPasswordLength
&& minPasswordLength
&& maxPasswordLength
== minPasswordLength
&& maxPasswordLength
!= defaultNumberOfRandomCharacters
){
930 useDefaultPasswordFormat
= CFSTR("false");
931 numberOfRequiredRandomCharacters
= maxPasswordLength
;
933 allowedCharacters
= (CFStringRef
)CFRetainSafe(CFDictionaryGetValue(requirements
, kSecPasswordAllowedCharactersKey
));
934 requiredCharactersArray
= (CFArrayRef
)CFDictionaryGetValue(requirements
, kSecPasswordRequiredCharactersKey
);
936 if (requiredCharactersArray
) {
937 for (CFIndex i
= 0; i
< CFArrayGetCount(requiredCharactersArray
); i
++){
938 CFCharacterSetRef stringWithRequiredCharacters
= CFArrayGetValueAtIndex(requiredCharactersArray
, i
);
939 if(stringWithRequiredCharacters
&& CFStringFindCharacterFromSet(allowedCharacters
, stringWithRequiredCharacters
, CFRangeMake(0, CFStringGetLength(allowedCharacters
)), 0, NULL
)){
940 CFArrayAppendValue(requiredCharacterSets
, stringWithRequiredCharacters
);
944 uppercaseLetterCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetUppercaseLetter
);
945 lowercaseLetterCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetLowercaseLetter
);
946 decimalDigitCharacterSet
= CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
);
947 CFArrayAppendValue(requiredCharacterSets
, uppercaseLetterCharacterSet
);
948 CFArrayAppendValue(requiredCharacterSets
, lowercaseLetterCharacterSet
);
949 CFArrayAppendValue(requiredCharacterSets
, decimalDigitCharacterSet
);
953 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordDisallowedCharacters
, &prohibitedCharacters
))
954 prohibitedCharacters
= NULL
;
956 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordCantEndWithChars
, &endWith
))
959 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordCantStartWithChars
, &startWith
))
962 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordGroupSize
, &groupSizeRef
))
965 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordNumberOfGroups
, &numberOfGroupsRef
))
966 numberOfGroupsRef
= NULL
;
968 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordSeparator
, &separatorRef
))
971 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordContainsNoMoreThanNSpecificCharacters
, &atMostCharactersRef
))
972 atMostCharactersRef
= NULL
;
974 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordContainsAtLeastNSpecificCharacters
, &atLeastCharactersRef
))
975 atLeastCharactersRef
= NULL
;
977 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordContainsNoMoreThanNConsecutiveIdenticalCharacters
, &identicalRef
))
980 if (allowedCharacters
) {
981 if( false == CFStringFindWithOptions(allowedCharacters
, CFSTR("-"), CFRangeMake(0, CFStringGetLength(allowedCharacters
)), kCFCompareCaseInsensitive
, NULL
))
982 useDefaultPasswordFormat
= CFSTR("false");
984 allowedCharacters
= CFRetainSafe(defaultCharacters
);
986 // In default password format, we use dashes only as separators, not as symbols you can encounter at a random position.
987 if (useDefaultPasswordFormat
== CFSTR("false")){
988 CFMutableStringRef mutatedAllowedCharacters
= CFStringCreateMutableCopy(kCFAllocatorDefault
, CFStringGetLength(allowedCharacters
), allowedCharacters
);
989 CFStringFindAndReplace (mutatedAllowedCharacters
, CFSTR("-"), CFSTR(""), CFRangeMake(0, CFStringGetLength(allowedCharacters
)),kCFCompareCaseInsensitive
);
990 CFReleaseSafe(allowedCharacters
);
991 allowedCharacters
= mutatedAllowedCharacters
;
994 if (CFArrayGetCount(requiredCharacterSets
) > numberOfRequiredRandomCharacters
) {
995 CFReleaseNull(requiredCharacterSets
);
996 requiredCharacterSets
= NULL
;
998 //create new CFDictionary
999 numReqChars
= CFNumberCreateWithCFIndex(kCFAllocatorDefault
, numberOfRequiredRandomCharacters
);
1000 CFMutableDictionaryRef updatedConstraints
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
1001 CFDictionaryAddValue(updatedConstraints
, kSecUseDefaultPasswordFormatKey
, useDefaultPasswordFormat
);
1002 CFDictionarySetValue(updatedConstraints
, kSecNumberOfRequiredRandomCharactersKey
, numReqChars
);
1003 CFDictionaryAddValue(updatedConstraints
, kSecAllowedCharactersKey
, allowedCharacters
);
1004 if(requiredCharacterSets
)
1005 CFDictionaryAddValue(updatedConstraints
, kSecRequiredCharacterSetsKey
, requiredCharacterSets
);
1007 //add the prohibited characters string if it exists to the new dictionary
1008 if(prohibitedCharacters
)
1009 CFDictionaryAddValue(updatedConstraints
, kSecPasswordDisallowedCharacters
, prohibitedCharacters
);
1011 //add the characters the password can't end with if it exists to the new dictionary
1013 CFDictionaryAddValue(updatedConstraints
, kSecPasswordCantEndWithChars
, endWith
);
1015 //add the characters the password can't start with if it exists to the new dictionary
1017 CFDictionaryAddValue(updatedConstraints
, kSecPasswordCantStartWithChars
, startWith
);
1020 CFDictionaryAddValue(updatedConstraints
, kSecPasswordGroupSize
, groupSizeRef
);
1022 if(numberOfGroupsRef
)
1023 CFDictionaryAddValue(updatedConstraints
, kSecPasswordNumberOfGroups
, numberOfGroupsRef
);
1026 CFDictionaryAddValue(updatedConstraints
, kSecPasswordSeparator
, separatorRef
);
1028 if(atMostCharactersRef
)
1029 CFDictionaryAddValue(updatedConstraints
, kSecPasswordContainsNoMoreThanNSpecificCharacters
, atMostCharactersRef
);
1031 if(atLeastCharactersRef
)
1032 CFDictionaryAddValue(updatedConstraints
, kSecPasswordContainsAtLeastNSpecificCharacters
, atLeastCharactersRef
);
1035 CFDictionaryAddValue(updatedConstraints
, kSecPasswordContainsNoMoreThanNConsecutiveIdenticalCharacters
, identicalRef
);
1037 CFReleaseNull(useDefaultPasswordFormat
);
1038 CFReleaseNull(numReqChars
);
1039 CFReleaseNull(allowedCharacters
);
1040 CFReleaseNull(requiredCharacterSets
);
1042 return updatedConstraints
;
1045 static bool isDictionaryFormattedProperly(SecPasswordType type
, CFDictionaryRef passwordRequirements
, CFErrorRef
*error
){
1047 CFTypeRef defaults
= NULL
;
1048 CFErrorRef tempError
= NULL
;
1049 if(passwordRequirements
== NULL
){
1053 if( CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordDefaultForType
, &defaults
) ){
1054 if(isString(defaults
) == true && 0 == CFStringCompare(defaults
, CFSTR("true"), 0)){
1058 //only need to check max and min pin length formatting
1059 if(type
== kSecPasswordTypePIN
){
1060 CFTypeRef minTest
= NULL
, maxTest
= NULL
;
1062 CFIndex minPasswordLength
= 0, maxPasswordLength
= 0;
1064 if( CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordDefaultForType
, &defaults
) ){
1065 if(isString(defaults
) == true && 0 == CFStringCompare(defaults
, CFSTR("true"), 0)){
1069 //check if the values exist!
1070 if( CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordMaxLengthKey
, &maxTest
) ){
1071 require_action_quiet(isNull(maxTest
)!= true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("To generate a password, need a max length"), (CFIndex
)errSecBadReq
, NULL
));
1072 require_action_quiet(isNumber(maxTest
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The password's max length must be a CFNumberRef"), (CFIndex
)errSecBadReq
, NULL
));
1075 if (CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordMinLengthKey
, &minTest
) ){
1076 require_action_quiet(isNull(minTest
)!= true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("To generate a password, need a min length"), (CFIndex
)errSecBadReq
, NULL
));
1077 require_action_quiet(isNumber(minTest
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The password's min length must be a CFNumberRef"), (CFIndex
)errSecBadReq
, NULL
));
1079 //check if the values exist!
1081 CFNumberRef max
= (CFNumberRef
)maxTest
;
1082 CFNumberGetValue(max
, kCFNumberSInt64Type
, &valuePtr
);
1083 maxPasswordLength
= (long)valuePtr
;
1086 CFNumberRef min
= (CFNumberRef
)minTest
;
1087 CFNumberGetValue(min
, kCFNumberSInt64Type
, &valuePtr
);
1088 minPasswordLength
= (long)valuePtr
;
1090 //make sure min and max make sense respective to each other and that they aren't less than 4 digits.
1091 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
));
1092 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
));
1095 CFTypeRef allowedTest
, maxTest
, minTest
, requiredTest
, prohibitedCharacters
, endWith
, startWith
,
1096 groupSizeRef
, numberOfGroupsRef
, separatorRef
, atMostCharactersRef
,
1097 atLeastCharactersRef
, thresholdRef
, identicalRef
, characters
;
1100 //check if the values exist!
1101 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
));
1102 require_action_quiet( CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordMaxLengthKey
, &maxTest
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("To generate a password, need a max length"), (CFIndex
)errSecBadReq
, NULL
));
1103 require_action_quiet( CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordMinLengthKey
, &minTest
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("To generate a password, need a min length"), (CFIndex
)errSecBadReq
, NULL
));
1104 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
));
1106 //check if values are null?
1107 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
));
1108 require_action_quiet(isNull(maxTest
)!= true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("To generate a password, need a max length"), (CFIndex
)errSecBadReq
, NULL
));
1109 require_action_quiet(isNull(minTest
)!= true, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("To generate a password, need a min length"), (CFIndex
)errSecBadReq
, NULL
));
1110 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
));
1112 //check if the values are correct
1113 require_action_quiet(isString(allowedTest
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The password's allowed characters must be a CFStringRef"), (CFIndex
)errSecBadReq
, NULL
));
1114 require_action_quiet(isNumber(maxTest
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The password's max length must be a CFNumberRef"), (CFIndex
)errSecBadReq
, NULL
));
1115 require_action_quiet(isNumber(minTest
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The password's min length must be a CFNumberRef"), (CFIndex
)errSecBadReq
, NULL
));
1116 require_action_quiet(isArray(requiredTest
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The password's required characters must be an array of CFCharacterSetRefs"), (CFIndex
)errSecBadReq
, NULL
));
1118 CFNumberGetValue(minTest
, kCFNumberSInt64Type
, &valuePtr
);
1119 CFIndex minPasswordLength
= (long)valuePtr
;
1120 CFNumberGetValue(maxTest
, kCFNumberSInt64Type
, &valuePtr
);
1121 CFIndex maxPasswordLength
= (long)valuePtr
;
1123 require_action_quiet(minPasswordLength
<= maxPasswordLength
, fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The password's length parameters make no sense ( is max < min ?)"), (CFIndex
)errSecBadReq
, NULL
));
1125 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
));
1126 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
));
1128 if(CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordDisallowedCharacters
, &prohibitedCharacters
)){
1129 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
));
1130 require_action_quiet(isString(prohibitedCharacters
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("Disallowed Characters dictionary parameter is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1132 if(CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordCantEndWithChars
, &endWith
)){
1133 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
));
1134 require_action_quiet(isString(endWith
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'EndWith' is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1136 if(CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordCantStartWithChars
, &startWith
)){
1137 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
));
1138 require_action_quiet(isString(startWith
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'StartWith' is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1140 if(CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordGroupSize
, &groupSizeRef
)){
1141 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
));
1142 require_action_quiet(isNumber(groupSizeRef
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'groupsize' is either null or not a number"), (CFIndex
)errSecBadReq
, NULL
));
1144 if(CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordNumberOfGroups
, &numberOfGroupsRef
)){
1145 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
));
1146 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
));
1148 if(CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordSeparator
, &separatorRef
)){
1149 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
));
1150 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
));
1153 if(CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordContainsNoMoreThanNSpecificCharacters
, &atMostCharactersRef
)){
1154 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
));
1155 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
));
1157 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
));
1158 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
));
1159 require_action_quiet(isNumber(thresholdRef
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'characters' is either null or not a number"), (CFIndex
)errSecBadReq
, NULL
));
1161 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
));
1162 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
));
1163 require_action_quiet(isString(characters
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'Characters' is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1166 if(CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordContainsAtLeastNSpecificCharacters
, &atLeastCharactersRef
)){
1167 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
));
1168 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
));
1170 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
));
1172 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
));
1173 require_action_quiet(isNumber(thresholdRef
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'characters' is either null or not a number"), (CFIndex
)errSecBadReq
, NULL
));
1175 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
));
1176 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
));
1177 require_action_quiet(isString(characters
), fail
, tempError
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("The dictionary parameter 'Characters' is either null or not a string"), (CFIndex
)errSecBadReq
, NULL
));
1180 if(CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordContainsNoMoreThanNConsecutiveIdenticalCharacters
, &identicalRef
)){
1181 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
));
1182 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
));
1189 if (tempError
!= NULL
) {
1191 *error
= CFRetainSafe(tempError
);
1195 CFReleaseNull(tempError
);
1200 static bool doesFinalPasswordPass(bool isSimple
, CFStringRef password
, CFDictionaryRef requirements
){
1202 CFTypeRef characters
, identicalRef
= NULL
, NRef
= NULL
, endWith
= NULL
, startWith
= NULL
, atLeastCharacters
= NULL
, atMostCharacters
= NULL
;
1204 CFIndex N
, identicalCount
;
1205 CFArrayRef requiredCharacterSet
= (CFArrayRef
)CFDictionaryGetValue(requirements
, kSecRequiredCharacterSetsKey
);
1207 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordCantEndWithChars
, &endWith
))
1210 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordCantStartWithChars
, &startWith
))
1213 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordContainsAtLeastNSpecificCharacters
, &atLeastCharacters
))
1214 atLeastCharacters
= NULL
;
1216 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordContainsNoMoreThanNSpecificCharacters
, &atMostCharacters
))
1217 atMostCharacters
= NULL
;
1219 if(!CFDictionaryGetValueIfPresent(requirements
, kSecPasswordContainsNoMoreThanNConsecutiveIdenticalCharacters
, &identicalRef
))
1220 identicalRef
= NULL
;
1222 CFNumberGetValue((CFNumberRef
)identicalRef
, kCFNumberSInt64Type
, &valuePtr
);
1223 identicalCount
= (long)valuePtr
;
1227 if(!doesPasswordEndWith(password
, endWith
))
1230 if(startWith
!= NULL
){
1231 if(!doesPasswordStartWith(password
, startWith
))
1234 if(atLeastCharacters
!= NULL
){
1235 NRef
= CFDictionaryGetValue(atLeastCharacters
, kSecPasswordCharacterCount
);
1236 characters
= CFDictionaryGetValue(atLeastCharacters
, kSecPasswordCharacters
);
1237 CFNumberGetValue((CFNumberRef
)NRef
, kCFNumberSInt64Type
, &valuePtr
);
1239 if(!passwordContainsAtLeastNCharacters(password
, characters
, N
))
1242 if(atMostCharacters
!= NULL
){
1243 NRef
= CFDictionaryGetValue(atMostCharacters
, kSecPasswordCharacterCount
);
1244 characters
= CFDictionaryGetValue(atMostCharacters
, kSecPasswordCharacters
);
1245 CFNumberGetValue((CFNumberRef
)NRef
, kCFNumberSInt64Type
, &valuePtr
);
1247 if(!passwordContainsLessThanNCharacters(password
, characters
, N
))
1250 if(identicalRef
!= NULL
){
1251 if(!passwordContainsLessThanNIdenticalCharacters(password
, identicalCount
))
1254 if (!passwordContainsRequiredCharacters(password
, requiredCharacterSet
))
1257 if(true == SecPasswordIsPasswordWeak2(isSimple
, password
))
1263 //entry point into password generation
1264 CF_RETURNS_RETAINED CFStringRef
SecPasswordGenerate(SecPasswordType type
, CFErrorRef
*error
, CFDictionaryRef passwordRequirements
){
1265 bool check
= false, isSimple
= false;
1266 CFTypeRef separator
= NULL
, defaults
= NULL
, groupSizeRef
= NULL
, numberOfGroupsRef
= NULL
;
1267 CFDictionaryRef properlyFormattedRequirements
= NULL
;
1268 CFErrorRef localError
= NULL
;
1269 uint64_t valuePtr
, groupSize
, numberOfGroups
;
1270 CFNumberRef numberOfRequiredRandomCharacters
;
1271 CFIndex requiredCharactersSize
;
1272 CFStringRef randomCharacters
= NULL
, password
= NULL
, allowedChars
= NULL
;
1273 CFMutableStringRef finalPassword
= NULL
;
1275 if(type
== kSecPasswordTypePIN
)
1279 check
= isDictionaryFormattedProperly(type
, passwordRequirements
, &localError
);
1280 require_quiet(check
!= false, fail
);
1282 //should we generate defaults?
1283 if(passwordRequirements
== NULL
|| (CFDictionaryGetValueIfPresent(passwordRequirements
, kSecPasswordDefaultForType
, &defaults
) && isString(defaults
) == true && 0 == CFStringCompare(defaults
, CFSTR("true"), 0) ))
1284 properlyFormattedRequirements
= passwordGenerateCreateDefaultParametersDictionary(type
, passwordRequirements
);
1286 properlyFormattedRequirements
= passwordGenerationCreateParametersDictionary(type
, passwordRequirements
);
1288 require_quiet(localError
== NULL
&& properlyFormattedRequirements
!= NULL
, fail
);
1290 numberOfRequiredRandomCharacters
= (CFNumberRef
)CFDictionaryGetValue(properlyFormattedRequirements
, kSecNumberOfRequiredRandomCharactersKey
);
1291 CFNumberGetValue(numberOfRequiredRandomCharacters
, kCFNumberSInt64Type
, &valuePtr
);
1292 requiredCharactersSize
= (long)valuePtr
;
1294 if(!CFDictionaryGetValueIfPresent(properlyFormattedRequirements
, kSecPasswordGroupSize
, &groupSizeRef
)){
1295 groupSizeRef
= NULL
;
1298 CFNumberGetValue((CFNumberRef
)groupSizeRef
, kCFNumberSInt64Type
, &groupSize
);
1300 if(!CFDictionaryGetValueIfPresent(properlyFormattedRequirements
, kSecPasswordNumberOfGroups
, &numberOfGroupsRef
)){
1301 numberOfGroupsRef
= NULL
;
1304 CFNumberGetValue((CFNumberRef
)numberOfGroupsRef
, kCFNumberSInt64Type
, &numberOfGroups
);
1307 allowedChars
= CFDictionaryGetValue(properlyFormattedRequirements
, kSecAllowedCharactersKey
);
1308 getPasswordRandomCharacters(&randomCharacters
, properlyFormattedRequirements
, &requiredCharactersSize
, allowedChars
);
1310 if(numberOfGroupsRef
&& groupSizeRef
){
1311 finalPassword
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
1313 if(!CFDictionaryGetValueIfPresent(properlyFormattedRequirements
, kSecPasswordSeparator
, &separator
))
1316 if(separator
== NULL
)
1317 separator
= CFSTR("-");
1320 while( i
!= requiredCharactersSize
){
1321 if((i
+ (CFIndex
)groupSize
) < requiredCharactersSize
){
1322 CFStringRef subString
= CFStringCreateWithSubstring(kCFAllocatorDefault
, randomCharacters
, CFRangeMake(i
, (CFIndex
)groupSize
));
1323 CFStringAppend(finalPassword
, subString
);
1324 CFStringAppend(finalPassword
, separator
);
1325 CFReleaseSafe(subString
);
1328 else if((i
+(CFIndex
)groupSize
) == requiredCharactersSize
){
1329 CFStringRef subString
= CFStringCreateWithSubstring(kCFAllocatorDefault
, randomCharacters
, CFRangeMake(i
, (CFIndex
)groupSize
));
1330 CFStringAppend(finalPassword
, subString
);
1331 CFReleaseSafe(subString
);
1335 CFStringRef subString
= CFStringCreateWithSubstring(kCFAllocatorDefault
, randomCharacters
, CFRangeMake(i
, requiredCharactersSize
- i
));
1336 CFStringAppend(finalPassword
, subString
);
1337 CFReleaseSafe(subString
);
1338 i
+=(requiredCharactersSize
- i
);
1341 password
= CFStringCreateCopy(kCFAllocatorDefault
, finalPassword
);
1342 CFReleaseNull(finalPassword
);
1344 //no fancy formatting
1346 password
= CFStringCreateCopy(kCFAllocatorDefault
, randomCharacters
);
1349 CFReleaseNull(randomCharacters
);
1350 require_quiet(doesFinalPasswordPass(isSimple
, password
, properlyFormattedRequirements
), no_pass
);
1351 CFReleaseNull(properlyFormattedRequirements
);
1355 CFReleaseNull(password
);
1359 if (error
&& localError
) {
1360 *error
= localError
;
1364 CFReleaseSafe(localError
);
1365 CFReleaseNull(properlyFormattedRequirements
);
1369 const char *in_word_set (const char *str
, unsigned int len
){
1370 static const char * wordlist
[] =
1372 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
1373 "", "", "0103", "", "", "", "", "0123", "", "", "", "", "0303", "", "", "",
1374 "", "", "", "", "0110", "", "1103", "", "", "", "", "1123", "", "", "0000",
1375 "", "1203", "", "0404", "", "", "", "", "1234", "1110", "2015", "2013", "",
1376 "2014", "1010", "2005", "2003", "", "2004", "1210", "0505", "0111", "", "",
1377 "", "2008", "0101", "", "2007", "", "", "", "", "2006", "2010", "1995", "1993",
1378 "", "1994", "2000", "", "1111", "", "", "", "1998", "1101", "", "1997", "",
1379 "0808", "1211", "", "1996", "0102", "", "1201", "", "", "1990", "", "", "",
1380 "", "0202", "", "2011", "", "", "1112", "1958", "2001", "", "1957", "1102",
1381 "", "3333", "", "1956", "1212", "1985", "1983", "", "1984", "1202", "", "0909",
1382 "", "0606", "", "1988", "1991", "", "1987", "2012", "", "", "", "1986", "2002",
1383 "", "", "", "0707", "1980", "", "2009", "", "", "2222", "1965", "1963", "",
1384 "1964", "", "", "2229", "", "", "1992", "1968", "", "", "1967", "", "", "1999",
1385 "", "1966", "", "1975", "1973", "", "1974", "1960", "", "1981", "", "4444",
1386 "", "1978", "", "7465", "1977", "", "", "", "", "1976", "2580", "", "1959",
1387 "", "", "1970", "", "", "", "", "", "", "", "", "", "1982", "", "1961", "",
1388 "", "5252", "", "1989", "", "", "", "", "", "", "", "", "", "", "", "", "",
1389 "", "1971", "", "", "", "", "", "", "", "1962", "", "5683", "", "6666", "",
1390 "", "1969", "", "", "", "", "", "", "", "", "", "", "", "", "1972", "", "",
1391 "", "", "", "", "1979", "", "", "", "7667"
1394 if (len
<= MAX_WORD_LENGTH
&& len
>= MIN_WORD_LENGTH
)
1396 register int key
= pinhash (str
, len
);
1398 if (key
<= MAX_HASH_VALUE
&& key
>= 0)
1400 register const char *s
= wordlist
[key
];
1401 if (*str
== *s
&& !strcmp (str
+ 1, s
+ 1))
1407 CFDictionaryRef
SecPasswordCopyDefaultPasswordLength(SecPasswordType type
, CFErrorRef
*error
){
1409 CFIndex tupleLengthInt
= 0, numOfTuplesInt
= 0;
1410 CFNumberRef tupleLength
= NULL
;
1411 CFNumberRef numOfTuples
= NULL
;
1413 CFMutableDictionaryRef passwordLengthDefaults
= NULL
;
1414 CFDictionaryRef result
= NULL
;
1417 case(kSecPasswordTypeiCloudRecovery
):
1422 case(kSecPasswordTypePIN
):
1427 case(kSecPasswordTypeSafari
):
1432 case(kSecPasswordTypeWifi
):
1438 if(SecError(errSecBadReq
, error
, CFSTR("Password type does not exist.")) == false)
1440 secdebug("secpasswordcopydefaultpasswordlength", "could not create error!");
1444 if (tupleLengthInt
!= 0 && numOfTuplesInt
!= 0) {
1445 tupleLength
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberCFIndexType
, &tupleLengthInt
);
1446 numOfTuples
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberCFIndexType
, &numOfTuplesInt
);
1447 passwordLengthDefaults
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
1448 CFDictionaryAddValue(passwordLengthDefaults
, kSecPasswordGroupSize
, tupleLength
);
1449 CFDictionaryAddValue(passwordLengthDefaults
, kSecPasswordNumberOfGroups
, numOfTuples
);
1450 result
= CFDictionaryCreateCopy(kCFAllocatorDefault
, passwordLengthDefaults
);
1453 CFReleaseSafe(tupleLength
);
1454 CFReleaseSafe(numOfTuples
);
1455 CFReleaseSafe(passwordLengthDefaults
);