2
0

Fix V0 in Java and support for testing algorithms.

This commit is contained in:
Maarten Billemont 2015-02-27 08:35:10 -05:00
parent 563aab9a81
commit 779d2776a0
8 changed files with 359 additions and 104 deletions

View File

@ -6,6 +6,7 @@ import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.jetbrains.annotations.Contract;
/** /**
@ -147,6 +148,7 @@ public enum MPSiteType {
* *
* @return The type registered with the given name. * @return The type registered with the given name.
*/ */
@Contract("!null -> !null, null -> null")
public static MPSiteType forName(@Nullable final String name) { public static MPSiteType forName(@Nullable final String name) {
if (name == null) if (name == null)

View File

@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList;
import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.List; import java.util.List;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.jetbrains.annotations.Contract;
/** /**
@ -66,6 +67,7 @@ public enum MPSiteVariant {
* *
* @return The variant registered with the given name. * @return The variant registered with the given name.
*/ */
@Contract("!null -> !null, null -> null")
public static MPSiteVariant forName(@Nullable final String name) { public static MPSiteVariant forName(@Nullable final String name) {
if (name == null) if (name == null)

View File

@ -89,29 +89,37 @@ public class MasterKeyV0 extends MasterKey {
byte[] siteNameBytes = siteName.getBytes( MP_charset ); byte[] siteNameBytes = siteName.getBytes( MP_charset );
byte[] siteNameLengthBytes = bytesForInt( siteName.length() ); byte[] siteNameLengthBytes = bytesForInt( siteName.length() );
byte[] siteCounterBytes = bytesForInt( siteCounter ); byte[] siteCounterBytes = bytesForInt( siteCounter );
byte[] siteContextBytes = siteContext == null? null: siteContext.getBytes( MP_charset ); byte[] siteContextBytes = siteContext == null || siteContext.isEmpty()? null: siteContext.getBytes( MP_charset );
byte[] siteContextLengthBytes = bytesForInt( siteContextBytes == null? 0: siteContextBytes.length ); byte[] siteContextLengthBytes = bytesForInt( siteContextBytes == null? 0: siteContextBytes.length );
logger.trc( "site scope: %s, context: %s", siteScope, siteContext == null? "<empty>": siteContext ); logger.trc( "site scope: %s, context: %s", siteScope, siteContextBytes == null? "<empty>": siteContext );
logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ), logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ),
siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ),
siteContext == null? "(null)": siteContext ); siteContextBytes == null? "(null)": siteContext );
byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MP_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes ); byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MP_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
if (siteContextBytes != null) if (siteContextBytes != null)
sitePasswordInfo = Bytes.concat( sitePasswordInfo, siteContextLengthBytes, siteContextBytes ); sitePasswordInfo = Bytes.concat( sitePasswordInfo, siteContextLengthBytes, siteContextBytes );
logger.trc( "sitePasswordInfo ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) ); logger.trc( "sitePasswordInfo ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
byte[] sitePasswordSeed = MP_mac.of( getKey(), sitePasswordInfo ); byte[] sitePasswordSeedBytes = MP_mac.of( getKey(), sitePasswordInfo );
logger.trc( "sitePasswordSeed ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeed ) ) ); int[] sitePasswordSeed = new int[sitePasswordSeedBytes.length];
for (int i = 0; i < sitePasswordSeedBytes.length; ++i) {
ByteBuffer buf = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( ByteOrder.BIG_ENDIAN );
Arrays.fill( buf.array(), sitePasswordSeedBytes[i] > 0? (byte)0x00: (byte) 0xFF );
buf.position( 2 );
buf.put( sitePasswordSeedBytes[i] ).rewind();
sitePasswordSeed[i] = buf.getInt() & 0xFFFF;
}
logger.trc( "sitePasswordSeed ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeedBytes ) ) );
Preconditions.checkState( sitePasswordSeed.length > 0 ); Preconditions.checkState( sitePasswordSeed.length > 0 );
int templateIndex = sitePasswordSeed[0] & 0xFFFF; int templateIndex = sitePasswordSeed[0];
MPTemplate template = siteType.getTemplateAtRollingIndex( templateIndex ); MPTemplate template = siteType.getTemplateAtRollingIndex( templateIndex );
logger.trc( "type %s, template: %s", siteType, template.getTemplateString() ); logger.trc( "type %s, template: %s", siteType, template.getTemplateString() );
StringBuilder password = new StringBuilder( template.length() ); StringBuilder password = new StringBuilder( template.length() );
for (int i = 0; i < template.length(); ++i) { for (int i = 0; i < template.length(); ++i) {
int characterIndex = sitePasswordSeed[i + 1] & 0xFFFF; int characterIndex = sitePasswordSeed[i + 1];
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i ); MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex ); char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
logger.trc( "class %c, index %d (0x%02X) -> character: %c", characterClass.getIdentifier(), characterIndex, logger.trc( "class %c, index %d (0x%02X) -> character: %c", characterClass.getIdentifier(), characterIndex,

View File

@ -46,12 +46,12 @@ public class MasterKeyV1 extends MasterKeyV0 {
byte[] siteNameBytes = siteName.getBytes( MP_charset ); byte[] siteNameBytes = siteName.getBytes( MP_charset );
byte[] siteNameLengthBytes = bytesForInt( siteName.length() ); byte[] siteNameLengthBytes = bytesForInt( siteName.length() );
byte[] siteCounterBytes = bytesForInt( siteCounter ); byte[] siteCounterBytes = bytesForInt( siteCounter );
byte[] siteContextBytes = siteContext == null? null: siteContext.getBytes( MP_charset ); byte[] siteContextBytes = siteContext == null || siteContext.isEmpty()? null: siteContext.getBytes( MP_charset );
byte[] siteContextLengthBytes = bytesForInt( siteContextBytes == null? 0: siteContextBytes.length ); byte[] siteContextLengthBytes = bytesForInt( siteContextBytes == null? 0: siteContextBytes.length );
logger.trc( "site scope: %s, context: %s", siteScope, siteContext == null? "<empty>": siteContext ); logger.trc( "site scope: %s, context: %s", siteScope, siteContextBytes == null? "<empty>": siteContext );
logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ), logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ),
siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ),
siteContext == null? "(null)": siteContext ); siteContextBytes == null? "(null)": siteContext );
byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MP_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes ); byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MP_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
if (siteContextBytes != null) if (siteContextBytes != null)

View File

@ -45,12 +45,12 @@ public class MasterKeyV2 extends MasterKeyV1 {
byte[] siteNameBytes = siteName.getBytes( MP_charset ); byte[] siteNameBytes = siteName.getBytes( MP_charset );
byte[] siteNameLengthBytes = bytesForInt( siteNameBytes.length ); byte[] siteNameLengthBytes = bytesForInt( siteNameBytes.length );
byte[] siteCounterBytes = bytesForInt( siteCounter ); byte[] siteCounterBytes = bytesForInt( siteCounter );
byte[] siteContextBytes = siteContext == null? null: siteContext.getBytes( MP_charset ); byte[] siteContextBytes = siteContext == null || siteContext.isEmpty()? null: siteContext.getBytes( MP_charset );
byte[] siteContextLengthBytes = bytesForInt( siteContextBytes == null? 0: siteContextBytes.length ); byte[] siteContextLengthBytes = bytesForInt( siteContextBytes == null? 0: siteContextBytes.length );
logger.trc( "site scope: %s, context: %s", siteScope, siteContext == null? "<empty>": siteContext ); logger.trc( "site scope: %s, context: %s", siteScope, siteContextBytes == null? "<empty>": siteContext );
logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ), logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ),
siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ),
siteContext == null? "(null)": siteContext ); siteContextBytes == null? "(null)": siteContext );
byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MP_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes ); byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MP_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
if (siteContextBytes != null) if (siteContextBytes != null)

View File

@ -1,10 +1,10 @@
package com.lyndir.masterpassword; package com.lyndir.masterpassword;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*; import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.lhunath.opal.system.util.NNSupplier; import com.lyndir.lhunath.opal.system.util.*;
import com.lyndir.lhunath.opal.system.util.NSupplier;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -25,8 +25,9 @@ public class MPWTests {
@XmlElement(name = "case") @XmlElement(name = "case")
private List<Case> cases; private List<Case> cases;
@Nonnull
public List<Case> getCases() { public List<Case> getCases() {
return cases; return checkNotNull( cases );
} }
public Case getCase(String identifier) { public Case getCase(String identifier) {
@ -45,6 +46,8 @@ public class MPWTests {
@XmlAttribute @XmlAttribute
private String parent; private String parent;
@XmlElement @XmlElement
private String algorithm;
@XmlElement
private String fullName; private String fullName;
@XmlElement @XmlElement
private String masterPassword; private String masterPassword;
@ -65,76 +68,86 @@ public class MPWTests {
private transient Case parentCase; private transient Case parentCase;
public void setTests(MPWTests tests) { public void initializeParentHierarchy(MPWTests tests) {
if (parent != null) { if (parent != null) {
parentCase = tests.getCase( parent ); parentCase = tests.getCase( parent );
fullName = ifNotNullElse( fullName, new NNSupplier<String>() { parentCase.initializeParentHierarchy( tests );
@Nonnull
@Override
public String get() {
return parentCase.getFullName();
}
} );
masterPassword = ifNotNullElse( masterPassword, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return new String( parentCase.getMasterPassword() );
}
} );
keyID = ifNotNullElse( keyID, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return parentCase.getKeyID();
}
} );
siteName = ifNotNullElse( siteName, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return parentCase.getSiteName();
}
} );
siteCounter = ifNotNullElse( siteCounter, new NNSupplier<Integer>() {
@Nonnull
@Override
public Integer get() {
return parentCase.getSiteCounter();
}
} );
siteType = ifNotNullElse( siteType, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return parentCase.getSiteType().name();
}
} );
siteVariant = ifNotNullElse( siteVariant, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return parentCase.getSiteVariant().name();
}
} );
siteContext = ifNotNullElseNullable( siteContext, new NSupplier<String>() {
@Nonnull
@Override
public String get() {
return parentCase.getSiteContext();
}
} );
result = ifNotNullElse( result, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return parentCase.getResult();
}
} );
} }
algorithm = ifNotNullElse( algorithm, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return checkNotNull( parentCase.algorithm );
}
} );
fullName = ifNotNullElse( fullName, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return checkNotNull( parentCase.fullName );
}
} );
masterPassword = ifNotNullElse( masterPassword, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return checkNotNull( parentCase.masterPassword );
}
} );
keyID = ifNotNullElse( keyID, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return checkNotNull( parentCase.keyID );
}
} );
siteName = ifNotNullElse( siteName, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return checkNotNull( parentCase.siteName );
}
} );
siteCounter = ifNotNullElse( siteCounter, new NNSupplier<Integer>() {
@Nonnull
@Override
public Integer get() {
return checkNotNull( parentCase.siteCounter );
}
} );
siteType = ifNotNullElse( siteType, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return checkNotNull( parentCase.siteType );
}
} );
siteVariant = ifNotNullElse( siteVariant, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return checkNotNull( parentCase.siteVariant );
}
} );
siteContext = ifNotNullElse( siteContext, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return parentCase == null? "": checkNotNull( parentCase.siteContext );
}
} );
result = ifNotNullElse( result, new NNSupplier<String>() {
@Nonnull
@Override
public String get() {
return parentCase == null? "": checkNotNull( parentCase.result );
}
} );
} }
@Nonnull
public String getIdentifier() { public String getIdentifier() {
return identifier; return identifier;
} }
@ -144,40 +157,53 @@ public class MPWTests {
return parentCase; return parentCase;
} }
@Nonnull
public MasterKey.Version getAlgorithm() {
return MasterKey.Version.fromInt( ConversionUtils.toIntegerNN( algorithm ) );
}
@Nonnull
public String getFullName() { public String getFullName() {
return fullName; return checkNotNull( fullName );
} }
@Nonnull
public char[] getMasterPassword() { public char[] getMasterPassword() {
return masterPassword == null? null: masterPassword.toCharArray(); return checkNotNull( masterPassword ).toCharArray();
} }
@Nonnull
public String getKeyID() { public String getKeyID() {
return keyID; return checkNotNull( keyID );
} }
@Nonnull
public String getSiteName() { public String getSiteName() {
return siteName; return checkNotNull( siteName );
} }
public int getSiteCounter() { public int getSiteCounter() {
return ifNotNullElse( siteCounter, 1 ); return ifNotNullElse( siteCounter, 1 );
} }
@Nonnull
public MPSiteType getSiteType() { public MPSiteType getSiteType() {
return MPSiteType.forName( siteType ); return MPSiteType.forName( checkNotNull( siteType ) );
} }
@Nonnull
public MPSiteVariant getSiteVariant() { public MPSiteVariant getSiteVariant() {
return MPSiteVariant.forName( siteVariant ); return MPSiteVariant.forName( checkNotNull( siteVariant ) );
} }
@Nonnull
public String getSiteContext() { public String getSiteContext() {
return siteContext; return checkNotNull( siteContext );
} }
@Nonnull
public String getResult() { public String getResult() {
return result; return checkNotNull( result );
} }
@Override @Override

View File

@ -5,6 +5,7 @@ import static org.testng.Assert.*;
import com.google.common.io.Resources; import com.google.common.io.Resources;
import com.lyndir.lhunath.opal.system.CodeUtils; import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.lhunath.opal.system.util.StringUtils;
import java.net.URL; import java.net.URL;
import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBContext;
import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeMethod;
@ -26,7 +27,7 @@ public class MasterKeyTest {
URL testCasesResource = Resources.getResource( "mpw_tests.xml" ); URL testCasesResource = Resources.getResource( "mpw_tests.xml" );
tests = (MPWTests) JAXBContext.newInstance( MPWTests.class ).createUnmarshaller().unmarshal( testCasesResource ); tests = (MPWTests) JAXBContext.newInstance( MPWTests.class ).createUnmarshaller().unmarshal( testCasesResource );
for (MPWTests.Case testCase : tests.getCases()) for (MPWTests.Case testCase : tests.getCases())
testCase.setTests( tests ); testCase.initializeParentHierarchy( tests );
defaultCase = tests.getCase( MPWTests.ID_DEFAULT ); defaultCase = tests.getCase( MPWTests.ID_DEFAULT );
} }
@ -35,10 +36,15 @@ public class MasterKeyTest {
throws Exception { throws Exception {
for (MPWTests.Case testCase : tests.getCases()) { for (MPWTests.Case testCase : tests.getCases()) {
MasterKey masterKey = MasterKey.create( testCase.getFullName(), testCase.getMasterPassword() ); if (testCase.getResult().isEmpty())
continue;
logger.inf( "Running test case: %s [testEncode]", testCase.getIdentifier() );
MasterKey masterKey = MasterKey.create( testCase.getAlgorithm(), testCase.getFullName(), testCase.getMasterPassword() );
assertEquals( assertEquals(
masterKey.encode( testCase.getSiteName(), testCase.getSiteType(), testCase.getSiteCounter(), testCase.getSiteVariant(), masterKey.encode( testCase.getSiteName(), testCase.getSiteType(), testCase.getSiteCounter(), testCase.getSiteVariant(),
testCase.getSiteContext() ), testCase.getResult(), "Failed test case: " + testCase ); testCase.getSiteContext() ), testCase.getResult(), "Failed test case: " + testCase );
logger.inf( "passed!" );
} }
} }
@ -55,8 +61,13 @@ public class MasterKeyTest {
throws Exception { throws Exception {
for (MPWTests.Case testCase : tests.getCases()) { for (MPWTests.Case testCase : tests.getCases()) {
if (testCase.getResult().isEmpty())
continue;
logger.inf( "Running test case: %s [testGetKeyID]", testCase.getIdentifier() );
MasterKey masterKey = MasterKey.create( testCase.getFullName(), testCase.getMasterPassword() ); MasterKey masterKey = MasterKey.create( testCase.getFullName(), testCase.getMasterPassword() );
assertEquals( CodeUtils.encodeHex( masterKey.getKeyID() ), testCase.getKeyID(), "Failed test case: " + testCase ); assertEquals( CodeUtils.encodeHex( masterKey.getKeyID() ), testCase.getKeyID(), "Failed test case: " + testCase );
logger.inf( "passed!" );
} }
} }

View File

@ -1,5 +1,7 @@
<tests> <tests>
<!-- Default values for all parameters. -->
<case id="default"> <case id="default">
<algorithm><!-- current --></algorithm>
<fullName>Robert Lee Mitchell</fullName> <fullName>Robert Lee Mitchell</fullName>
<masterPassword>banana colored duckling</masterPassword> <masterPassword>banana colored duckling</masterPassword>
<keyID>98EEF4D1DF46D849574A82A03C3177056B15DFFCA29BB3899DE4628453675302</keyID> <keyID>98EEF4D1DF46D849574A82A03C3177056B15DFFCA29BB3899DE4628453675302</keyID>
@ -7,67 +9,271 @@
<siteCounter>1</siteCounter> <siteCounter>1</siteCounter>
<siteType>GeneratedLong</siteType> <siteType>GeneratedLong</siteType>
<siteVariant>Password</siteVariant> <siteVariant>Password</siteVariant>
<result><!-- abstract --></result>
</case>
<!-- Algorithm 3 -->
<case id="v3" parent="default">
<algorithm>3</algorithm>
<result>Jejr5[RepuSosp</result> <result>Jejr5[RepuSosp</result>
</case> </case>
<case id="mb_fullName" parent="default"> <case id="v3_mb_fullName" parent="v3">
<fullName></fullName> <fullName></fullName>
<keyID>1717AA1F9BF5BA56CD0965CDA3D78E6D2E6A1EA8C067A8EA621F3DDAD4A87EB8</keyID> <keyID>1717AA1F9BF5BA56CD0965CDA3D78E6D2E6A1EA8C067A8EA621F3DDAD4A87EB8</keyID>
<result>NopaDajh8=Fene</result> <result>NopaDajh8=Fene</result>
</case> </case>
<case id="mb_masterPassword" parent="default"> <case id="v3_mb_masterPassword" parent="v3">
<masterPassword></masterPassword> <masterPassword></masterPassword>
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID> <keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
<result>QesuHirv5-Xepl</result> <result>QesuHirv5-Xepl</result>
</case> </case>
<case id="mb_siteName" parent="default"> <case id="v3_mb_siteName" parent="v3">
<siteName></siteName> <siteName></siteName>
<result>LiheCuwhSerz6)</result> <result>LiheCuwhSerz6)</result>
</case> </case>
<case id="loginName" parent="default"> <case id="v3_loginName" parent="v3">
<siteVariant>Login</siteVariant> <siteVariant>Login</siteVariant>
<siteType>GeneratedName</siteType> <siteType>GeneratedName</siteType>
<result>wohzaqage</result> <result>wohzaqage</result>
</case> </case>
<case id="securityAnswer" parent="default"> <case id="v3_securityAnswer" parent="v3">
<siteVariant>Answer</siteVariant> <siteVariant>Answer</siteVariant>
<siteType>GeneratedPhrase</siteType> <siteType>GeneratedPhrase</siteType>
<result>xin diyjiqoja hubu</result> <result>xin diyjiqoja hubu</result>
</case> </case>
<case id="securityAnswer_context" parent="securityAnswer"> <case id="v3_securityAnswer_context" parent="v3_securityAnswer">
<siteContext>question</siteContext> <siteContext>question</siteContext>
<result>xogx tem cegyiva jab</result> <result>xogx tem cegyiva jab</result>
</case> </case>
<case id="type_maximum" parent="default"> <case id="v3_type_maximum" parent="v3">
<siteType>GeneratedMaximum</siteType> <siteType>GeneratedMaximum</siteType>
<result>W6@692^B1#&amp;@gVdSdLZ@</result> <result>W6@692^B1#&amp;@gVdSdLZ@</result>
</case> </case>
<case id="type_medium" parent="default"> <case id="v3_type_medium" parent="v3">
<siteType>GeneratedMedium</siteType> <siteType>GeneratedMedium</siteType>
<result>Jej2$Quv</result> <result>Jej2$Quv</result>
</case> </case>
<case id="type_basic" parent="default"> <case id="v3_type_basic" parent="v3">
<siteType>GeneratedBasic</siteType> <siteType>GeneratedBasic</siteType>
<result>WAo2xIg6</result> <result>WAo2xIg6</result>
</case> </case>
<case id="type_short" parent="default"> <case id="v3_type_short" parent="v3">
<siteType>GeneratedShort</siteType> <siteType>GeneratedShort</siteType>
<result>Jej2</result> <result>Jej2</result>
</case> </case>
<case id="type_pin" parent="default"> <case id="v3_type_pin" parent="v3">
<siteType>GeneratedPIN</siteType> <siteType>GeneratedPIN</siteType>
<result>7662</result> <result>7662</result>
</case> </case>
<case id="type_name" parent="default"> <case id="v3_type_name" parent="v3">
<siteType>GeneratedName</siteType> <siteType>GeneratedName</siteType>
<result>jejraquvo</result> <result>jejraquvo</result>
</case> </case>
<case id="type_phrase" parent="default"> <case id="v3_type_phrase" parent="v3">
<siteType>GeneratedPhrase</siteType> <siteType>GeneratedPhrase</siteType>
<result>jejr quv cabsibu tam</result> <result>jejr quv cabsibu tam</result>
</case> </case>
<case id="counter_ceiling" parent="default"> <case id="v3_counter_ceiling" parent="v3">
<siteCounter>4294967295</siteCounter> <siteCounter>4294967295</siteCounter>
<result>XambHoqo6[Peni</result> <result>XambHoqo6[Peni</result>
</case> </case>
<!-- Algorithm 2 -->
<case id="v2" parent="default">
<algorithm>2</algorithm>
<result>Jejr5[RepuSosp</result>
</case>
<case id="v2_mb_fullName" parent="v2">
<fullName></fullName>
<keyID>1717AA1F9BF5BA56CD0965CDA3D78E6D2E6A1EA8C067A8EA621F3DDAD4A87EB8</keyID>
<result>WaqoGuho2[Xaxw</result>
</case>
<case id="v2_mb_masterPassword" parent="v2">
<masterPassword></masterPassword>
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
<result>QesuHirv5-Xepl</result>
</case>
<case id="v2_mb_siteName" parent="v2">
<siteName></siteName>
<result>LiheCuwhSerz6)</result>
</case>
<case id="v2_loginName" parent="v2">
<siteVariant>Login</siteVariant>
<siteType>GeneratedName</siteType>
<result>wohzaqage</result>
</case>
<case id="v2_securityAnswer" parent="v2">
<siteVariant>Answer</siteVariant>
<siteType>GeneratedPhrase</siteType>
<result>xin diyjiqoja hubu</result>
</case>
<case id="v2_securityAnswer_context" parent="v2_securityAnswer">
<siteContext>question</siteContext>
<result>xogx tem cegyiva jab</result>
</case>
<case id="v2_type_maximum" parent="v2">
<siteType>GeneratedMaximum</siteType>
<result>W6@692^B1#&amp;@gVdSdLZ@</result>
</case>
<case id="v2_type_medium" parent="v2">
<siteType>GeneratedMedium</siteType>
<result>Jej2$Quv</result>
</case>
<case id="v2_type_basic" parent="v2">
<siteType>GeneratedBasic</siteType>
<result>WAo2xIg6</result>
</case>
<case id="v2_type_short" parent="v2">
<siteType>GeneratedShort</siteType>
<result>Jej2</result>
</case>
<case id="v2_type_pin" parent="v2">
<siteType>GeneratedPIN</siteType>
<result>7662</result>
</case>
<case id="v2_type_name" parent="v2">
<siteType>GeneratedName</siteType>
<result>jejraquvo</result>
</case>
<case id="v2_type_phrase" parent="v2">
<siteType>GeneratedPhrase</siteType>
<result>jejr quv cabsibu tam</result>
</case>
<case id="v2_counter_ceiling" parent="v2">
<siteCounter>4294967295</siteCounter>
<result>XambHoqo6[Peni</result>
</case>
<!-- Algorithm 1 -->
<case id="v1" parent="default">
<algorithm>1</algorithm>
<result>Jejr5[RepuSosp</result>
</case>
<case id="v1_mb_fullName" parent="v1">
<fullName></fullName>
<keyID>1717AA1F9BF5BA56CD0965CDA3D78E6D2E6A1EA8C067A8EA621F3DDAD4A87EB8</keyID>
<result>WaqoGuho2[Xaxw</result>
</case>
<case id="v1_mb_masterPassword" parent="v1">
<masterPassword></masterPassword>
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
<result>QesuHirv5-Xepl</result>
</case>
<case id="v1_mb_siteName" parent="v1">
<siteName></siteName>
<result>WawiYarp2@Kodh</result>
</case>
<case id="v1_loginName" parent="v1">
<siteVariant>Login</siteVariant>
<siteType>GeneratedName</siteType>
<result>wohzaqage</result>
</case>
<case id="v1_securityAnswer" parent="v1">
<siteVariant>Answer</siteVariant>
<siteType>GeneratedPhrase</siteType>
<result>xin diyjiqoja hubu</result>
</case>
<case id="v1_securityAnswer_context" parent="v1_securityAnswer">
<siteContext>question</siteContext>
<result>xogx tem cegyiva jab</result>
</case>
<case id="v1_type_maximum" parent="v1">
<siteType>GeneratedMaximum</siteType>
<result>W6@692^B1#&amp;@gVdSdLZ@</result>
</case>
<case id="v1_type_medium" parent="v1">
<siteType>GeneratedMedium</siteType>
<result>Jej2$Quv</result>
</case>
<case id="v1_type_basic" parent="v1">
<siteType>GeneratedBasic</siteType>
<result>WAo2xIg6</result>
</case>
<case id="v1_type_short" parent="v1">
<siteType>GeneratedShort</siteType>
<result>Jej2</result>
</case>
<case id="v1_type_pin" parent="v1">
<siteType>GeneratedPIN</siteType>
<result>7662</result>
</case>
<case id="v1_type_name" parent="v1">
<siteType>GeneratedName</siteType>
<result>jejraquvo</result>
</case>
<case id="v1_type_phrase" parent="v1">
<siteType>GeneratedPhrase</siteType>
<result>jejr quv cabsibu tam</result>
</case>
<case id="v1_counter_ceiling" parent="v1">
<siteCounter>4294967295</siteCounter>
<result>XambHoqo6[Peni</result>
</case>
<!-- Algorithm 0 -->
<case id="v0" parent="default">
<algorithm>0</algorithm>
<result>Feji5@ReduWosh</result>
</case>
<case id="v0_mb_fullName" parent="v0">
<fullName></fullName>
<keyID>1717AA1F9BF5BA56CD0965CDA3D78E6D2E6A1EA8C067A8EA621F3DDAD4A87EB8</keyID>
<result>HajrYudo7@Mamh</result>
</case>
<case id="v0_mb_masterPassword" parent="v0">
<masterPassword></masterPassword>
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
<result>MewmDini0]Meho</result>
</case>
<case id="v0_mb_siteName" parent="v0">
<siteName></siteName>
<result>HahiVana2@Nole</result>
</case>
<case id="v0_loginName" parent="v0">
<siteVariant>Login</siteVariant>
<siteType>GeneratedName</siteType>
<result>lozwajave</result>
</case>
<case id="v0_securityAnswer" parent="v0">
<siteVariant>Answer</siteVariant>
<siteType>GeneratedPhrase</siteType>
<result>miy lirfijoja dubu</result>
</case>
<case id="v0_securityAnswer_context" parent="v0_securityAnswer">
<siteContext>question</siteContext>
<result>movm bex gevrica jaf</result>
</case>
<case id="v0_type_maximum" parent="v0">
<siteType>GeneratedMaximum</siteType>
<result>w1!3bA3icmRAc)SS@lwl</result>
</case>
<case id="v0_type_medium" parent="v0">
<siteType>GeneratedMedium</siteType>
<result>Fej7]Jug</result>
</case>
<case id="v0_type_basic" parent="v0">
<siteType>GeneratedBasic</siteType>
<result>wvH7irC1</result>
</case>
<case id="v0_type_short" parent="v0">
<siteType>GeneratedShort</siteType>
<result>Fej7</result>
</case>
<case id="v0_type_pin" parent="v0">
<siteType>GeneratedPIN</siteType>
<result>2117</result>
</case>
<case id="v0_type_name" parent="v0">
<siteType>GeneratedName</siteType>
<result>fejrajugo</result>
</case>
<case id="v0_type_phrase" parent="v0">
<siteType>GeneratedPhrase</siteType>
<result>fejr jug gabsibu bax</result>
</case>
<case id="v0_counter_ceiling" parent="v0">
<siteCounter>4294967295</siteCounter>
<result>QateDojh1@Hecn</result>
</case>
</tests> </tests>