2
0

A Java proof-of-concept CLI for Master Password.

This commit is contained in:
Maarten Billemont 2012-07-05 00:09:03 +02:00
parent 0e8e4dc06d
commit 04a6c8e68d
50 changed files with 834 additions and 0 deletions

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- PROJECT METADATA -->
<parent>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<artifactId>masterpassword</artifactId>
<version>GIT-SNAPSHOT</version>
</parent>
<name>Master Password Algorithm Implementation</name>
<description>The implementation of the Master Password algorithm</description>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<artifactId>masterpassword-algorithm</artifactId>
<packaging>jar</packaging>
<!-- DEPENDENCY MANAGEMENT -->
<dependencies>
<!-- PROJECT REFERENCES -->
<dependency>
<groupId>com.lyndir.lhunath.opal</groupId>
<artifactId>opal-system</artifactId>
<version>GIT-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.lyndir.lhunath.opal</groupId>
<artifactId>opal-crypto</artifactId>
<version>GIT-SNAPSHOT</version>
</dependency>
<!-- EXTERNAL DEPENDENCIES -->
<dependency>
<groupId>net.sf.plist</groupId>
<artifactId>property-list</artifactId>
<version>svn-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.lambdaworks</groupId>
<artifactId>scrypt</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,14 @@
package com.lyndir.lhunath.masterpassword;
/**
* <i>07 04, 2012</i>
*
* @author lhunath
*/
public enum MPElementFeature {
/** Export the key-protected content data. */
ExportContent,
/** Never export content. */
DevicePrivate,
}

View File

@ -0,0 +1,79 @@
package com.lyndir.lhunath.masterpassword;
import com.google.common.collect.ImmutableSet;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.Set;
/**
* <i>07 04, 2012</i>
*
* @author lhunath
*/
public enum MPElementType {
GeneratedMaximum( "Maximum Security Password", "Maximum", "20 characters, contains symbols.", MPElementTypeClass.Generated ),
GeneratedLong( "Long Password", "Long", "Copy-friendly, 14 characters, contains symbols.", MPElementTypeClass.Generated ),
GeneratedMedium( "Medium Password", "Medium", "Copy-friendly, 8 characters, contains symbols.", MPElementTypeClass.Generated ),
GeneratedShort( "Short Password", "Short", "Copy-friendly, 4 characters, no symbols.", MPElementTypeClass.Generated ),
GeneratedBasic( "Basic Password", "Basic", "8 characters, no symbols.", MPElementTypeClass.Generated ),
GeneratedPIN( "PIN", "PIN", "4 numbers.", MPElementTypeClass.Generated ),
StoredPersonal( "Personal Password", "Personal", "AES-encrypted, exportable.", MPElementTypeClass.Stored, MPElementFeature.ExportContent ),
StoredDevicePrivate( "Device Private Password", "Private", "AES-encrypted, not exported.", MPElementTypeClass.Stored, MPElementFeature.DevicePrivate );
static final Logger logger = Logger.get( MPElementType.class );
private final MPElementTypeClass typeClass;
private final Set<MPElementFeature> typeFeatures;
private final String name;
private final String shortName;
private final String description;
MPElementType(final String name, final String shortName, final String description, final MPElementTypeClass typeClass, final MPElementFeature... typeFeatures) {
this.name = name;
this.shortName = shortName;
this.typeClass = typeClass;
this.description = description;
ImmutableSet.Builder<MPElementFeature> typeFeaturesBuilder = ImmutableSet.builder();
for (final MPElementFeature typeFeature : typeFeatures)
typeFeaturesBuilder.add( typeFeature );
this.typeFeatures = typeFeaturesBuilder.build();
}
public MPElementTypeClass getTypeClass() {
return typeClass;
}
public Set<MPElementFeature> getTypeFeatures() {
return typeFeatures;
}
public String getName() {
return name;
}
public String getShortName() {
return shortName;
}
public String getDescription() {
return description;
}
public static MPElementType forName(final String name) {
for (final MPElementType type : values())
if (type.getName().equals( name ))
return type;
throw logger.bug( "Element type not known: %s", name );
}
}

View File

@ -0,0 +1,27 @@
package com.lyndir.lhunath.masterpassword;
import com.lyndir.lhunath.masterpassword.entity.*;
/**
* <i>07 04, 2012</i>
*
* @author lhunath
*/
public enum MPElementTypeClass {
Generated(MPElementGeneratedEntity.class),
Stored(MPElementStoredEntity.class);
private final Class<? extends MPElementEntity> entityClass;
MPElementTypeClass(final Class<? extends MPElementEntity> entityClass) {
this.entityClass = entityClass;
}
public Class<? extends MPElementEntity> getEntityClass() {
return entityClass;
}
}

View File

@ -0,0 +1,41 @@
package com.lyndir.lhunath.masterpassword;
import com.google.common.collect.ImmutableList;
import com.lyndir.lhunath.opal.system.util.MetaObject;
import java.util.List;
import java.util.Map;
/**
* <i>07 04, 2012</i>
*
* @author lhunath
*/
public class MPTemplate extends MetaObject {
private final List<MPTemplateCharacterClass> template;
public MPTemplate(final String template, final Map<Character, MPTemplateCharacterClass> characterClasses) {
ImmutableList.Builder<MPTemplateCharacterClass> builder = ImmutableList.<MPTemplateCharacterClass>builder();
for (int i = 0; i < template.length(); ++i)
builder.add( characterClasses.get( template.charAt( i ) ) );
this.template = builder.build();
}
public MPTemplate(final List<MPTemplateCharacterClass> template) {
this.template = template;
}
public MPTemplateCharacterClass getCharacterClassAtIndex(final int index) {
return template.get( index );
}
public int length() {
return template.size();
}
}

View File

@ -0,0 +1,33 @@
package com.lyndir.lhunath.masterpassword;
import com.lyndir.lhunath.opal.system.util.MetaObject;
import com.lyndir.lhunath.opal.system.util.ObjectMeta;
/**
* <i>07 04, 2012</i>
*
* @author lhunath
*/
public class MPTemplateCharacterClass extends MetaObject {
private final char identifier;
@ObjectMeta(useFor = { })
private final char[] characters;
public MPTemplateCharacterClass(final char identifier, final char[] characters) {
this.identifier = identifier;
this.characters = characters;
}
public char getIdentifier() {
return identifier;
}
public char getCharacterAtRollingIndex(final int index) {
return characters[index % characters.length];
}
}

View File

@ -0,0 +1,103 @@
package com.lyndir.lhunath.masterpassword;
import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.Closeables;
import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.lhunath.opal.system.util.MetaObject;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import net.sf.plist.*;
import net.sf.plist.io.PropertyListException;
import net.sf.plist.io.PropertyListParser;
/**
* <i>07 04, 2012</i>
*
* @author lhunath
*/
public class MPTemplates extends MetaObject {
static final Logger logger = Logger.get( MPTemplates.class );
private final Map<MPElementType, List<MPTemplate>> templates;
public MPTemplates(final Map<MPElementType, List<MPTemplate>> templates) {
this.templates = templates;
}
public static MPTemplates loadFromPList(final String templateResource) {
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
InputStream templateStream = Thread.currentThread().getContextClassLoader().getResourceAsStream( templateResource );
try {
NSObject plistObject = PropertyListParser.parse( templateStream );
Preconditions.checkState( NSDictionary.class.isAssignableFrom( plistObject.getClass() ) );
NSDictionary plist = (NSDictionary) plistObject;
NSDictionary characterClassesDict = (NSDictionary) plist.get( "MPCharacterClasses" );
NSDictionary templatesDict = (NSDictionary) plist.get( "MPElementGeneratedEntity" );
ImmutableMap.Builder<Character, MPTemplateCharacterClass> characterClassesBuilder = ImmutableMap.builder();
for (final Map.Entry<String, NSObject> characterClassEntry : characterClassesDict.entrySet()) {
String key = characterClassEntry.getKey();
NSObject value = characterClassEntry.getValue();
Preconditions.checkState( key.length() == 1 );
Preconditions.checkState( NSString.class.isAssignableFrom( value.getClass() ));
char character = key.charAt( 0 );
char[] characterClass = ((NSString)value).getValue().toCharArray();
characterClassesBuilder.put( character, new MPTemplateCharacterClass( character, characterClass ) );
}
ImmutableMap<Character, MPTemplateCharacterClass> characterClasses = characterClassesBuilder.build();
ImmutableMap.Builder<MPElementType, List<MPTemplate>> templatesBuilder = ImmutableMap.builder();
for (final Map.Entry<String, NSObject> template : templatesDict.entrySet()) {
String key = template.getKey();
NSObject value = template.getValue();
Preconditions.checkState( NSArray.class.isAssignableFrom( value.getClass() ) );
MPElementType type = MPElementType.forName( key );
List<NSObject> templateStrings = ((NSArray) value).getValue();
ImmutableList.Builder<MPTemplate> typeTemplatesBuilder = ImmutableList.<MPTemplate>builder();
for (final NSObject templateString : templateStrings)
typeTemplatesBuilder.add( new MPTemplate( ((NSString) templateString).getValue(), characterClasses ) );
templatesBuilder.put( type, typeTemplatesBuilder.build() );
}
ImmutableMap<MPElementType, List<MPTemplate>> templates = templatesBuilder.build();
return new MPTemplates( templates );
}
catch (PropertyListException e) {
logger.err( e, "Could not parse templates from: %s", templateResource );
throw Throwables.propagate( e );
}
catch (IOException e) {
logger.err( e, "Could not read templates from: %s", templateResource );
throw Throwables.propagate( e );
}
finally {
Closeables.closeQuietly( templateStream );
}
}
public MPTemplate getTemplateForTypeAtRollingIndex(final MPElementType type, final int templateIndex) {
List<MPTemplate> typeTemplates = templates.get( type );
return typeTemplates.get( templateIndex % typeTemplates.size() );
}
public static void main(final String... arguments) {
loadFromPList( "templates.plist" );
}
}

View File

@ -0,0 +1,128 @@
package com.lyndir.lhunath.masterpassword;
import com.google.common.base.Charsets;
import com.google.common.base.Preconditions;
import com.google.common.primitives.Bytes;
import com.lambdaworks.crypto.SCrypt;
import com.lyndir.lhunath.opal.crypto.CryptUtils;
import com.lyndir.lhunath.opal.system.*;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
/**
* Implementation of the Master Password algorithm.
*
* <i>07 04, 2012</i>
*
* @author lhunath
*/
public abstract class MasterPassword {
static final Logger logger = Logger.get( MasterPassword.class );
private static final int MP_N = 32768;
private static final int MP_r = 8;
private static final int MP_p = 2;
private static final int MP_dkLen = 64;
private static final Charset MP_charset = Charsets.UTF_8;
private static final ByteOrder MP_byteOrder = ByteOrder.BIG_ENDIAN;
private static final MessageDigests MP_hash = MessageDigests.SHA256;
private static final MessageAuthenticationDigests MP_mac = MessageAuthenticationDigests.HmacSHA256;
private static final MPTemplates templates = MPTemplates.loadFromPList( "templates.plist" );
public static byte[] keyForPassword(final String password, final String username) {
long start = System.currentTimeMillis();
byte[] nusernameLengthBytes = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE )
.order( MP_byteOrder )
.putInt( username.length() )
.array();
byte[] salt = Bytes.concat( "com.lyndir.masterpassword".getBytes( MP_charset ), //
nusernameLengthBytes, //
username.getBytes( MP_charset ) );
try {
byte[] key = SCrypt.scrypt( password.getBytes( MP_charset ), salt, MP_N, MP_r, MP_p, MP_dkLen );
logger.trc( "User: %s, password: %s derives to key ID: %s (took %.2fs)", username, password,
CodeUtils.encodeHex( keyIDForKey( key ) ), (double) (System.currentTimeMillis() - start) / 1000 );
return key;
}
catch (GeneralSecurityException e) {
throw logger.bug( e );
}
}
public static byte[] subkeyForKey(final byte[] key, final int subkeyLength) {
byte[] subkey = new byte[Math.min( subkeyLength, key.length )];
System.arraycopy( key, 0, subkey, 0, subkey.length );
return subkey;
}
public static byte[] keyIDForPassword(final String password, final String username) {
return keyIDForKey( keyForPassword( password, username ) );
}
public static byte[] keyIDForKey(final byte[] key) {
return MP_hash.of( key );
}
public static String generateContent(final MPElementType type, final String name, final byte[] key, int counter) {
Preconditions.checkArgument( type.getTypeClass() == MPElementTypeClass.Generated );
Preconditions.checkArgument( !name.isEmpty() );
Preconditions.checkArgument( key.length > 0 );
if (counter == 0)
counter = (int) (System.currentTimeMillis() / (300 * 1000)) * 300;
byte[] nameLengthBytes = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( MP_byteOrder ).putInt( name.length() ).array();
byte[] counterBytes = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( MP_byteOrder ).putInt( counter ).array();
logger.trc( "seed from: hmac-sha256(%s, 'com.lyndir.masterpassword' | %s | %s | %s)", CryptUtils.encodeBase64( key ),
CodeUtils.encodeHex( nameLengthBytes ), name, CodeUtils.encodeHex( counterBytes ) );
byte[] seed = MP_mac.of( key, Bytes.concat( "com.lyndir.masterpassword".getBytes( MP_charset ), //
nameLengthBytes, //
name.getBytes( MP_charset ), //
counterBytes ) );
logger.trc( "seed is: %s", CryptUtils.encodeBase64( seed ) );
Preconditions.checkState( seed.length > 0 );
int templateIndex = seed[0] & 0xFF; // Mask the integer's sign.
MPTemplate template = templates.getTemplateForTypeAtRollingIndex( type, templateIndex );
logger.trc( "type: %s, template: %s", type, template );
StringBuilder password = new StringBuilder( template.length() );
for (int i = 0; i < template.length(); ++i) {
int characterIndex = seed[i + 1] & 0xFF; // Mask the integer's sign.
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
logger.trc( "class: %s, index: %d, byte: 0x%02X, chosen password character: %s", characterClass, characterIndex, seed[i + 1],
passwordCharacter );
password.append( passwordCharacter );
}
return password.toString();
}
public static void main(final String... arguments) {
String masterPassword = "test-mp";
String username = "test-user";
String siteName = "test-site";
MPElementType siteType = MPElementType.GeneratedLong;
int siteCounter = 42;
String sitePassword = generateContent( siteType, siteName, keyForPassword( masterPassword, username ), siteCounter );
logger.inf( "master password: %s, username: %s\nsite name: %s, site type: %s, site counter: %d\n => site password: %s",
masterPassword, username, siteName, siteType, siteCounter, sitePassword );
}
}

View File

@ -0,0 +1,10 @@
package com.lyndir.lhunath.masterpassword.entity;
/**
* <i>07 04, 2012</i>
*
* @author lhunath
*/
public class MPElementEntity {
}

View File

@ -0,0 +1,10 @@
package com.lyndir.lhunath.masterpassword.entity;
/**
* <i>07 04, 2012</i>
*
* @author lhunath
*/
public class MPElementGeneratedEntity extends MPElementEntity {
}

View File

@ -0,0 +1,10 @@
package com.lyndir.lhunath.masterpassword.entity;
/**
* <i>07 04, 2012</i>
*
* @author lhunath
*/
public class MPElementStoredEntity extends MPElementEntity {
}

View File

@ -0,0 +1 @@
../../../../../../Resources/ciphers.plist

View File

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>MPElementGeneratedEntity</key>
<dict>
<key>Maximum Security Password</key>
<array>
<string>anoxxxxxxxxxxxxxxxxx</string>
<string>axxxxxxxxxxxxxxxxxno</string>
</array>
<key>Long Password</key>
<array>
<string>CvcvnoCvcvCvcv</string>
<string>CvcvCvcvnoCvcv</string>
<string>CvcvCvcvCvcvno</string>
<string>CvccnoCvcvCvcv</string>
<string>CvccCvcvnoCvcv</string>
<string>CvccCvcvCvcvno</string>
<string>CvcvnoCvccCvcv</string>
<string>CvcvCvccnoCvcv</string>
<string>CvcvCvccCvcvno</string>
<string>CvcvnoCvcvCvcc</string>
<string>CvcvCvcvnoCvcc</string>
<string>CvcvCvcvCvccno</string>
<string>CvccnoCvccCvcv</string>
<string>CvccCvccnoCvcv</string>
<string>CvccCvccCvcvno</string>
<string>CvcvnoCvccCvcc</string>
<string>CvcvCvccnoCvcc</string>
<string>CvcvCvccCvccno</string>
<string>CvccnoCvcvCvcc</string>
<string>CvccCvcvnoCvcc</string>
<string>CvccCvcvCvccno</string>
</array>
<key>Medium Password</key>
<array>
<string>CvcnoCvc</string>
<string>CvcCvcno</string>
</array>
<key>Short Password</key>
<array>
<string>Cvcn</string>
</array>
<key>Basic Password</key>
<array>
<string>aaanaaan</string>
<string>aannaaan</string>
<string>aaannaaa</string>
</array>
<key>PIN</key>
<array>
<string>nnnn</string>
</array>
</dict>
<key>MPCharacterClasses</key>
<dict>
<key>V</key>
<string>AEIOU</string>
<key>C</key>
<string>BCDFGHJKLMNPQRSTVWXYZ</string>
<key>v</key>
<string>aeiou</string>
<key>c</key>
<string>bcdfghjklmnpqrstvwxyz</string>
<key>A</key>
<string>AEIOUBCDFGHJKLMNPQRSTVWXYZ</string>
<key>a</key>
<string>AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz</string>
<key>n</key>
<string>0123456789</string>
<key>o</key>
<string>@&amp;%?,=[]_:-+*$#!'^~;()/.</string>
<key>x</key>
<string>AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&amp;*()</string>
</dict>
</dict>
</plist>

View File

@ -0,0 +1,5 @@
#Generated by Maven
#Wed Jul 04 23:49:38 CEST 2012
version=GIT-SNAPSHOT
groupId=com.lyndir.lhunath.masterpassword
artifactId=masterpassword-algorithm

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- PROJECT METADATA -->
<parent>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<artifactId>masterpassword</artifactId>
<version>GIT-SNAPSHOT</version>
</parent>
<name>Master Password CLI</name>
<description>A CLI interface to the Master Password algorithm</description>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<artifactId>masterpassword-cli</artifactId>
<packaging>jar</packaging>
<!-- BUILD CONFIGURATION -->
<build>
<resources>
<resource>
<directory>src/main/scripts</directory>
<filtering>true</filtering>
<targetPath>${project.build.directory}</targetPath>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.lyndir.lhunath.masterpassword.CLI</mainClass>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<!-- DEPENDENCY MANAGEMENT -->
<dependencies>
<!-- PROJECT REFERENCES -->
<dependency>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<artifactId>masterpassword-algorithm</artifactId>
<version>GIT-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,108 @@
/*
* Copyright 2008, Maarten Billemont
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.lyndir.lhunath.masterpassword;
import com.google.common.io.LineReader;
import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
import java.io.*;
import java.util.Arrays;
/**
* <p> <i>Jun 10, 2008</i> </p>
*
* @author mbillemo
*/
public class CLI {
static final Logger logger = Logger.get( CLI.class );
public static void main(final String[] args)
throws IOException {
InputStream in = System.in;
/* Arguments. */
String userName = null, siteName = null;
int counter = 1;
MPElementType type = MPElementType.GeneratedLong;
boolean typeArg = false, counterArg = false, userNameArg = false;
for (final String arg : Arrays.asList( args ))
if ("-t".equals( arg ) || "--type".equals( arg ))
typeArg = true;
else if (typeArg) {
if ("list".equalsIgnoreCase( arg )) {
System.out.format( "%30s | %s\n", "type", "description" );
for (final MPElementType aType : MPElementType.values())
System.out.format( "%30s | %s\n", aType.getName(), aType.getDescription() );
System.exit( 0 );
}
type = MPElementType.forName( arg );
typeArg = false;
} else if ("-c".equals( arg ) || "--counter".equals( arg ))
counterArg = true;
else if (counterArg) {
counter = ConversionUtils.toIntegerNN( arg );
counterArg = false;
} else if ("-u".equals( arg ) || "--username".equals( arg ))
userNameArg = true;
else if (userNameArg) {
userName = arg;
userNameArg = false;
} else if ("-h".equals( arg ) || "--help".equals( arg )) {
System.out.println();
System.out.println( "\tMaster Password CLI" );
System.out.println( "\t\tLyndir" );
System.out.println( "[options] [site name]" );
System.out.println();
System.out.println( "Available options:" );
System.out.println( "\t-t | --type [site password type]" );
System.out.format( "\t\tDefault: %s. The password type to use for this site.\n", type.getName() );
System.out.println( "\t\tUse 'list' to see the available types." );
System.out.println();
System.out.println( "\t-c | --counter [site counter]" );
System.out.format( "\t\tDefault: %d. The counter to use for this site.\n", counter );
System.out.println( "\t\tIncrement the counter if you need a new password." );
System.out.println();
System.out.println( "\t-u | --username [user's name]" );
System.out.println( "\t\tDefault: asked. The name of the current user." );
System.out.println();
return;
} else
siteName = arg;
LineReader lineReader = new LineReader( new InputStreamReader( System.in ) );
if (siteName == null) {
System.out.print( "Site name: " );
siteName = lineReader.readLine();
}
if (userName == null) {
System.out.print( "User's name: " );
userName = lineReader.readLine();
}
System.out.print( "User's master password: " );
String masterPassword = lineReader.readLine();
String sitePassword = MasterPassword.generateContent( type, siteName, MasterPassword.keyForPassword( masterPassword, userName ),
counter );
System.out.println( sitePassword );
}
}

View File

@ -0,0 +1,19 @@
<configuration scan="true">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%-8relative %22c{0} [%-5level] %msg%n</Pattern>
</layout>
</appender>
<logger name="com.lyndir" level="TRACE" />
<!--
<logger name="org.apache.wicket" level="DEBUG" />
-->
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
cd "${BASH_SOURCE[0]%/*}"
java -jar masterpassword-cli-GIT-SNAPSHOT.jar "$@"

View File

@ -0,0 +1,5 @@
#Generated by Maven
#Wed Jul 04 23:49:39 CEST 2012
version=GIT-SNAPSHOT
groupId=com.lyndir.lhunath.masterpassword
artifactId=masterpassword-cli

View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
cd "${BASH_SOURCE[0]%/*}"
java -jar masterpassword-cli-GIT-SNAPSHOT.jar "$@"

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- PROJECT METADATA -->
<parent>
<groupId>com.lyndir.lhunath</groupId>
<artifactId>lyndir</artifactId>
<version>GIT-SNAPSHOT</version>
</parent>
<name>Master Password</name>
<description>A Java implementation of the Master Password algorithm.</description>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<artifactId>masterpassword</artifactId>
<version>GIT-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>masterpassword-algorithm</module>
<module>masterpassword-cli</module>
</modules>
</project>