/// <summary> /// Replace the current character with a random replacement /// </summary> /// <param name="c"></param> /// <returns></returns> public static Char RandomCharacterReplacement(Char character, Random random) { Char newChar; do { newChar = DataGenHelpers.GetRandomAlphaNumericCharacter(random); } while (newChar == character); // try again if we end up with the same character return(newChar); }
/// <summary> /// Insert a random character in the passed in source /// </summary> /// <param name="soure"></param> /// <returns></returns> public String InsertRandomCharacter(String source) { // Ramdonly pick a spot to insert at. Weigh the positional end point a bit heavier than the overall // length of the source string so we get some more chances that characters get appended // to the end of the string. Int32 pos = this.random.Next(0, source.Length + 1); // Pick a random character to insert Char c = DataGenHelpers.GetRandomAlphaNumericCharacter(random); StringBuilder sb = new StringBuilder(source); if (pos >= source.Length) { sb.Append(c); } else { sb.Insert(pos, c); } return(sb.ToString()); }
/// <summary> /// Walks through the ConsumerTrust records and fuzzes them according to the configurable settings /// </summary> private void FuzzConsumerTrust(RandomNumberGenerator random) { Int32 fuzzCount = 0; Int32 nicknameAttempts = 0; // do until we have reached the number of records that are supposed to be fuzzed while (fuzzCount < Properties.Settings.Default.TrustSideFuzzCount) { // Get a random Credit Card out of the TrustSideCreditCard table DataSetDebtDataGenerator.TrustCreditCardRow trustCreditCardRow = this.dataSetDebtDataGen.TrustCreditCard[random.Next(this.dataSetDebtDataGen.TrustCreditCard.Count)]; // Ensure that the credit card is a matching one. The reason we fuzz only match candidates is so we can compare // the ACTUAL results of the server's actual matching algorithm to our EXPECTED value of matches. if (!this.dataSetDebtDataGen.RealCreditCard[trustCreditCardRow.RealCreditCardId].IsMatched) { continue; } // Ensure that the Credit Card we retrieved (OR its Consumer) has not already been fuzzed by either the // Common Fuzz heuristics or here in this method. IF FuzzedFields is any value other than "none" the // record has been fuzzed. if (trustCreditCardRow.FuzzedFields != Convert.ToInt32(CreditCardFuzzedFields.None) || trustCreditCardRow.TrustSideConsumerRow.FuzzedFields != Convert.ToInt32(ConsumerFuzzedFields.None)) { continue; } // *** If we get to this point, we have a candiate for fuzzing *** // Get the Credit Card's corresponding consumer DataSetDebtDataGenerator.TrustSideConsumerRow trustConsumer = trustCreditCardRow.TrustSideConsumerRow; // fulfill the 'constant' requirements first if (!TrustNickNamePercentageIsMet(fuzzCount)) { // We're not always guaranteed that a particular consumer is going to have a shortened first name // or nickname. Therefore we use this clause to force a known percentage to be fulfilled by picking // through and finding the consumer records that actually do have them. string nickname; if (TryGetRealConsumerNickName(trustConsumer.RealConsumerId, out nickname)) { trustConsumer.FirstName = nickname; trustConsumer.FuzzedFields = Convert.ToInt32(ConsumerFuzzedFields.FirstName); trustConsumer.FuzzMethod = Convert.ToInt32(FuzzMethod.NicknameSubstitution); } else { // This consumer did not have a nickname so go get another one and try again // We may not have enough first names to satisfy the nickname criteria. A 'reasonable enough' number // of attempts is three times the size of the TrustSideConsumerTable. // Note: [skt] I've run across some seeds that cause this exception to be thrown. This is relatively // rare. The easiest thing to do is just pick another random seed and gen the data again. if (++nicknameAttempts > this.dataSetDebtDataGen.TrustSideConsumer.Count * 3) { throw new SystemException( String.Format( " Data Generation Failed. Exceeded the number of valid attempts ({0}) to reach nickname percentage.", this.dataSetDebtDataGen.TrustSideConsumer.Count * 3)); } continue; } } else // fulfill the remaining fuzzCount with different variations of fuzzed data { // roll the dice to see what gets fuzzzed switch (random.Next(1, 7)) { // one third of the time we will fuzz the SSN case 1: case 2: { // 30 percent of the time we fuzz the SSN, it will be character subtraction if (random.Next(100).IsWithinRange(0, 29)) { // flip a coin to determine whether or not we omit a middle character or one on the end if (random.Next(100).IsWithinRange(0, 49)) { // omit a character in the middle FuzzSocialSecurityNumber(trustConsumer, FuzzMethod.MissingRandomMiddleCharacter, random); trustConsumer.FuzzMethod = Convert.ToInt32(FuzzMethod.MissingRandomMiddleCharacter); } else { // omit an endpoint character: Flip a coin to determine which end if (random.Next(100).IsWithinRange(0, 49)) { // first char FuzzSocialSecurityNumber(trustConsumer, FuzzMethod.MissingFirstCharacter, random); trustConsumer.FuzzMethod = Convert.ToInt32(FuzzMethod.MissingFirstCharacter); } else { // last char FuzzSocialSecurityNumber(trustConsumer, FuzzMethod.MissingLastCharacter, random); trustConsumer.FuzzMethod = Convert.ToInt32(FuzzMethod.MissingLastCharacter); } } } // 70 percent of the time we will fat finger this field else { // determine the fat-finger-technique if (random.Next(100).IsWithinRange(0, 74)) { // 'accidentally' swapping characters 75% of the time FuzzSocialSecurityNumber(trustConsumer, FuzzMethod.AdjacentCharactersSwapped, random); trustConsumer.FuzzMethod = Convert.ToInt32(FuzzMethod.AdjacentCharactersSwapped); } else { // adding an extra 'random' character 25% of the time FuzzSocialSecurityNumber(trustConsumer, FuzzMethod.RandomCharacterAdded, random); trustConsumer.FuzzMethod = Convert.ToInt32(FuzzMethod.RandomCharacterAdded); } } // mark that the SSN was fuzzed trustConsumer.FuzzedFields = Convert.ToInt32(ConsumerFuzzedFields.SocialSecurityNumber); break; } // one third of the time we will fuzz the matched consumer's CCN case 3: case 4: { // 25 percent of the time we fuzz the CCN, it will be character subtraction if (random.Next(100).IsWithinRange(0, 24)) { // flip a coin to determine whether or not we omit a middle character or one on the end if (random.Next(100).IsWithinRange(0, 49)) { // omit a character in the middle FuzzCreditCardNumber(trustCreditCardRow, FuzzMethod.MissingRandomMiddleCharacter, random); trustCreditCardRow.FuzzMethod = Convert.ToInt32(FuzzMethod.MissingRandomMiddleCharacter); } else { // omit an endpoint character: Flip a coin to determine which end if (random.Next(100).IsWithinRange(0, 49)) { // first char FuzzCreditCardNumber(trustCreditCardRow, FuzzMethod.MissingFirstCharacter, random); trustCreditCardRow.FuzzMethod = Convert.ToInt32(FuzzMethod.MissingFirstCharacter); } else { // last char FuzzCreditCardNumber(trustCreditCardRow, FuzzMethod.MissingLastCharacter, random); trustCreditCardRow.FuzzMethod = Convert.ToInt32(FuzzMethod.MissingLastCharacter); } } } // 75 percent of the time we will fat finger this field: else { // determine the fat-finger-technique if (random.Next(100).IsWithinRange(0, 74)) { // 'accidentally' swapping characters 75% of the time FuzzCreditCardNumber(trustCreditCardRow, FuzzMethod.AdjacentCharactersSwapped, random); trustCreditCardRow.FuzzMethod = Convert.ToInt32(FuzzMethod.AdjacentCharactersSwapped); } else { // adding an extra 'random' character 25% of the time FuzzCreditCardNumber(trustCreditCardRow, FuzzMethod.RandomCharacterAdded, random); trustCreditCardRow.FuzzMethod = Convert.ToInt32(FuzzMethod.RandomCharacterAdded); } } // mark the credit card to say that its CCN has been fuzzed trustCreditCardRow.FuzzedFields = Convert.ToInt32(CreditCardFuzzedFields.CreditCardNumber); break; } // one sixth of the time we will fuzz both case 5: { // fat fingering - accidentally swapping characters FuzzSocialSecurityNumber(trustConsumer, FuzzMethod.AdjacentCharactersSwapped, random); FuzzCreditCardNumber(trustCreditCardRow, FuzzMethod.AdjacentCharactersSwapped, random); // mark that both SSN and CCN were fuzzed trustConsumer.FuzzedFields = Convert.ToInt32(ConsumerFuzzedFields.SocialSecurityNumber); trustConsumer.FuzzMethod = Convert.ToInt32(FuzzMethod.AdjacentCharactersSwapped); trustCreditCardRow.FuzzedFields = Convert.ToInt32(CreditCardFuzzedFields.CreditCardNumber); trustCreditCardRow.FuzzMethod = Convert.ToInt32(FuzzMethod.AdjacentCharactersSwapped); break; } // One-sixth of the time we will muck with the consumer's name. case 6: { // If both FN/LN fields are empty... if (trustConsumer.FirstName == null && trustConsumer.LastName == null) { // add a couple random characters into the LN field trustConsumer.LastName = Convert.ToString(DataGenHelpers.GetRandomAlphaNumericCharacter(random)); trustConsumer.LastName += Convert.ToString(DataGenHelpers.GetRandomAlphaNumericCharacter(random)); // mark that the last name has been fuzzed with a whole new name trustConsumer.FuzzedFields = Convert.ToInt32(ConsumerFuzzedFields.LastName); trustConsumer.FuzzMethod = Convert.ToInt32(FuzzMethod.CompletelyNewValue); } // Flip a 3-sided coin (http://www.statisticool.com/3sided.htm) to determine how we muck with the name switch (random.Next(1, 4)) { case 1: // First Name Muck { if (trustConsumer.FirstName == null) { // If the field is empty, add a random character trustConsumer.FirstName = Convert.ToString(DataGenHelpers.GetRandomAlphaNumericCharacter(random)); trustConsumer.FuzzMethod = Convert.ToInt32(FuzzMethod.CompletelyNewValue); } else if (trustConsumer.FirstName.Length == 1) { // FN is already one char in length, so swap it with another (i.e, a screwed-up first initial) trustConsumer.FirstName = Convert.ToString(DataGenHelpers.RandomCharacterReplacement(trustConsumer.FirstName[0], random)); trustConsumer.FuzzMethod = Convert.ToInt32(FuzzMethod.CompletelyNewValue); } else { // first name is > 1 characters, strip it down to just one trustConsumer.FirstName = trustConsumer.FirstName.Substring(0, 1); trustConsumer.FuzzMethod = Convert.ToInt32(FuzzMethod.StrippedDownToFirstCharacterOnly); } // mark that the firstname has been fuzzed trustConsumer.FuzzedFields = Convert.ToInt32(ConsumerFuzzedFields.FirstName); break; } case 2: // Last Name Muck { // Replace the last name altogether (someone got married/divorced/etc...) String newLastName = this.lastNameList[random.Next(0, this.lastNameList.Count - 1)]; while (newLastName == trustConsumer.LastName) { // if we happen to get the same name, try again newLastName = this.lastNameList[random.Next(0, this.lastNameList.Count - 1)]; } // Flip a coin to see if we hyphenate or replace it altogether // [skt] can refine this by gender if the need arises (put a gender column in the consumer tables) if (random.Next(100).IsWithinRange(0, 49)) { // hyphenate trustConsumer.LastName = String.Format("{0}-{1}", trustConsumer.LastName, newLastName[0] + newLastName.Substring(1, newLastName.Length - 1).ToLower()); trustConsumer.FuzzMethod = Convert.ToInt32(FuzzMethod.CompletelyNewValueHyphenated); } else { // new name, no hyphenation trustConsumer.LastName = newLastName.ToLower(); trustConsumer.FuzzMethod = Convert.ToInt32(FuzzMethod.CompletelyNewValue); } // mark that the last name has been fuzzed with a whole new name trustConsumer.FuzzedFields = Convert.ToInt32(ConsumerFuzzedFields.LastName); break; } case 3: // swap FN and LN { string tmp = trustConsumer.FirstName; trustConsumer.FirstName = trustConsumer.LastName; trustConsumer.LastName = tmp; // mark that both FN and LN were fuzzed trustConsumer.FuzzedFields = Convert.ToInt32(ConsumerFuzzedFields.FirstName) | Convert.ToInt32(ConsumerFuzzedFields.LastName); trustConsumer.FuzzMethod = Convert.ToInt32(FuzzMethod.Swapped); break; } } break; } } } // increment the count of how many records we fuzzed ++fuzzCount; } }