From eb7f1ddcd78f71cf479d7f717b9242204c09f679 Mon Sep 17 00:00:00 2001 From: Nathaniel Wesley Filardo Date: Thu, 8 Jul 2010 01:21:43 -0400 Subject: [PATCH] Initial checkin --- AndroidManifest.xml | 29 + build.properties | 17 + build.xml | 62 ++ default.properties | 11 + .../ietfng/ns/android/vcpass/VCSlideGen.java | 201 ++++++ .../ns/android/vcpass/VCTestVocGen.java | 207 ++++++ res/drawable-hdpi/icon.png | Bin 0 -> 4147 bytes res/drawable-ldpi/icon.png | Bin 0 -> 1723 bytes res/drawable-mdpi/icon.png | Bin 0 -> 2574 bytes res/layout/main.xml | 13 + res/layout/vcpact.xml | 30 + res/layout/vcpimp.xml | 29 + res/values/dimens.xml | 4 + res/values/strings.xml | 9 + src/org/ietfng/ns/android/vcpass/Utils.java | 46 ++ .../ietfng/ns/android/vcpass/VCGenerator.java | 335 +++++++++ .../ns/android/vcpass/VCParameters.java | 41 ++ src/org/ietfng/ns/android/vcpass/VCPass.java | 223 ++++++ .../ns/android/vcpass/VCPassActivity.java | 665 ++++++++++++++++++ .../ns/android/vcpass/VCPassImport.java | 255 +++++++ tests/AndroidManifest.xml | 21 + tests/build.properties | 15 + tests/build.xml | 61 ++ tests/default.properties | 11 + tests/local.properties | 11 + .../ietfng/ns/android/vcpass/VCPassTest.java | 21 + 26 files changed, 2317 insertions(+) create mode 100644 AndroidManifest.xml create mode 100644 build.properties create mode 100644 build.xml create mode 100644 default.properties create mode 100644 host/org/ietfng/ns/android/vcpass/VCSlideGen.java create mode 100644 host/org/ietfng/ns/android/vcpass/VCTestVocGen.java create mode 100644 res/drawable-hdpi/icon.png create mode 100644 res/drawable-ldpi/icon.png create mode 100644 res/drawable-mdpi/icon.png create mode 100644 res/layout/main.xml create mode 100644 res/layout/vcpact.xml create mode 100644 res/layout/vcpimp.xml create mode 100644 res/values/dimens.xml create mode 100644 res/values/strings.xml create mode 100644 src/org/ietfng/ns/android/vcpass/Utils.java create mode 100644 src/org/ietfng/ns/android/vcpass/VCGenerator.java create mode 100644 src/org/ietfng/ns/android/vcpass/VCParameters.java create mode 100644 src/org/ietfng/ns/android/vcpass/VCPass.java create mode 100644 src/org/ietfng/ns/android/vcpass/VCPassActivity.java create mode 100644 src/org/ietfng/ns/android/vcpass/VCPassImport.java create mode 100644 tests/AndroidManifest.xml create mode 100644 tests/build.properties create mode 100644 tests/build.xml create mode 100644 tests/default.properties create mode 100644 tests/local.properties create mode 100644 tests/src/org/ietfng/ns/android/vcpass/VCPassTest.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml new file mode 100644 index 0000000..c982d87 --- /dev/null +++ b/AndroidManifest.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build.properties b/build.properties new file mode 100644 index 0000000..edc7f23 --- /dev/null +++ b/build.properties @@ -0,0 +1,17 @@ +# This file is used to override default values used by the Ant build system. +# +# This file must be checked in Version Control Systems, as it is +# integral to the build system of your project. + +# This file is only used by the Ant script. + +# You can use this to override default values such as +# 'source.dir' for the location of your java source folder and +# 'out.dir' for the location of your output folder. + +# You can also use it define how the release builds are signed by declaring +# the following properties: +# 'key.store' for the location of your keystore and +# 'key.alias' for the name of the key to use. +# The password will be asked during the build when you use the 'release' target. + diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..af37263 --- /dev/null +++ b/build.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/default.properties b/default.properties new file mode 100644 index 0000000..9d79b12 --- /dev/null +++ b/default.properties @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "build.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=android-4 diff --git a/host/org/ietfng/ns/android/vcpass/VCSlideGen.java b/host/org/ietfng/ns/android/vcpass/VCSlideGen.java new file mode 100644 index 0000000..5329e7d --- /dev/null +++ b/host/org/ietfng/ns/android/vcpass/VCSlideGen.java @@ -0,0 +1,201 @@ +/** Host-side slide generator. + * + * Required classpath entries: + * /usr/share/java/bcprov.jar + * /usr/share/java/commons-codec.jar + * /usr/share/java/commons-cli.jar + * $HOME/src/zxing/core/core.jar + * + * Build with: + * javac -d bin/classes -cp bin/classes:... \ + * host/org/ietfng/ns/android/vcpass/VCSlideGen.java + * + */ + +package org.ietfng.ns.android.vcpass; + +import java.io.FileWriter; +import java.security.SecureRandom; +import java.security.Provider; +import java.security.Security; +import javax.crypto.SecretKey; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.MultiFormatWriter; +import com.google.zxing.common.ByteMatrix; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.PosixParser; +import org.apache.commons.codec.binary.Base64; + +public final class VCSlideGen { + static final private int SEED_SIZE = 16; + + private static final int QR_SIZEX = 400; + private static final int QR_SIZEY = 400; + + static final private Options cliopts = new Options(); + static final private String OPT_SS_HELP = "h"; + static final private String OPT_SS_QRFILE = "b"; + static final private String OPT_SS_SECRET = "S"; + static final private String OPT_SS_SLIDEF = "s"; + static final private String OPT_SS_VOCABS = "v"; + + private static final int crpix = VCParameters.DISP_X + / VCParameters.GRID_X; + private static final int ccpix = VCParameters.DISP_Y + / VCParameters.GRID_Y; + + private static final void + printPBMHeader(FileWriter f, int v, int x, int y) + throws java.io.IOException + { + StringBuilder sb = new StringBuilder(); + sb.append("P"); + sb.append(v); + sb.append(" "); + sb.append(x); + sb.append(" "); + sb.append(y); + sb.append("\n"); + f.write(sb.toString(), 0, sb.length()); + } + + static { + cliopts.addOption(OPT_SS_HELP, "help", false, "Show this help"); + cliopts.addOption(OPT_SS_QRFILE, "qrfile", true, + "Barcode PNM file basename"); + cliopts.addOption(OPT_SS_SECRET, "secretseed", true, + "Secret seed (for development)"); + cliopts.addOption(OPT_SS_SLIDEF, "slidefile", true, + "Slide PNM file basename"); + cliopts.addOption(OPT_SS_VOCABS, "vocabfile", true, + "Vocabulary PNM file basename"); + } + + public static void main(String[] args) throws Exception { + CommandLineParser parser = new PosixParser(); + CommandLine cmd = parser.parse(cliopts, args); + + if(cmd.hasOption(OPT_SS_HELP)) { + HelpFormatter formatter = new HelpFormatter(); + formatter.printHelp( "VCSlideGen" , cliopts ); + return; + } + + Security.addProvider(VCParameters.CSPROV); + +/* XXX */ + char[] useed = "foo".toCharArray(); + char[] vseed = "bar".toCharArray(); + +/* XXX + byte[] useed = new byte[SEED_SIZE]; + byte[] vseed = new byte[SEED_SIZE]; + + { + SecureRandom seedsr = SecureRandom.getInstance( + VCParameters.CSPRNG + ); + if(cmd.hasOption(OPT_SS_SECRET)) { + System.err.println("WARN: Using given seed."); + seedsr.setSeed(cmd.getOptionValue(OPT_SS_SECRET) + .getBytes("UTF-8")); + } else { + // seedsr will initialize from the system's RNG when + // we first pull some data out of it. + } + seedsr.nextBytes(useed); + seedsr.nextBytes(vseed); + } +*/ + + if(cmd.hasOption(OPT_SS_QRFILE)) { + String encodedseeds = null; + { + StringBuilder esb = new StringBuilder(); + Base64 b64 = new Base64(80,new byte[0]); + // XXX esb.append(b64.encodeToString(useed)); + esb.append(" "); + // XXX esb.append(b64.encodeToString(vseed)); + encodedseeds = esb.toString(); + System.out.printf("QRSTR: %s\n", encodedseeds); + } + FileWriter qrout = new FileWriter( + cmd.getOptionValue(OPT_SS_QRFILE) + +".pbm" + ); + printPBMHeader(qrout, 1, QR_SIZEX, QR_SIZEY); + ByteMatrix qrbm = new MultiFormatWriter().encode( + encodedseeds, + BarcodeFormat.QR_CODE, + QR_SIZEX, QR_SIZEY); + byte[][] qr = qrbm.getArray(); + for(int x = 0; x < qr.length; x++) { + for(int y = 0; y < qr[x].length; y++) { + qrout.write('1' - (qr[x][y] & 0x1)); + } + qrout.write('\n'); + } + qrout.flush(); + qrout.close(); + } + + if(cmd.hasOption(OPT_SS_SLIDEF)) { + FileWriter sout = new FileWriter( + cmd.getOptionValue(OPT_SS_SLIDEF) + +".pbm" + ); + printPBMHeader(sout, 1, VCParameters.DISP_X, + VCParameters.DISP_Y); + + Integer[][] slide = VCGenerator.generateSlide(useed, null); + + int[][] pixels = VCGenerator.vcArrayToPixels(slide); + for(int r = 0; r < pixels.length; r++) { + for(int c = 0; c < pixels[r].length; c++) { + sout.write(pixels[r][c] == VCParameters.white ? + '0' : '1'); + } + sout.write('\n'); + } + sout.flush(); + sout.close(); + } + + if(cmd.hasOption(OPT_SS_VOCABS)) { + int[] plain = new int[VCParameters.GRID_X + *VCParameters.GRID_Y]; + for(int i = 0; i < VCParameters.VCVOC_SIZE; i++) { + FileWriter vout = new FileWriter( + cmd.getOptionValue(OPT_SS_VOCABS) + +"-" + +Integer.toString(i) + +".pbm" + ); + printPBMHeader(vout, 1, VCParameters.DISP_X, + VCParameters.DISP_Y); + + for(int j = 0; j < plain.length; j++) { + plain[j] = i; + } + + Integer[][] vocab = VCGenerator.generateChallenge( + vseed, useed, plain, null + ); + int[][] pixels = VCGenerator.vcArrayToPixels(vocab); + for(int r = 0; r < pixels.length; r++) { + for(int c = 0; c < pixels[r].length; c++) { + vout.write(pixels[r][c] == VCParameters.white ? + '1' : '0'); + } + vout.write('\n'); + } + vout.flush(); + vout.close(); + } + } + } +} diff --git a/host/org/ietfng/ns/android/vcpass/VCTestVocGen.java b/host/org/ietfng/ns/android/vcpass/VCTestVocGen.java new file mode 100644 index 0000000..bc871e6 --- /dev/null +++ b/host/org/ietfng/ns/android/vcpass/VCTestVocGen.java @@ -0,0 +1,207 @@ +/** Host-side slide generator. + * + * Required classpath entries: + * /usr/share/java/bcprov.jar + * /usr/share/java/commons-codec.jar + * /usr/share/java/commons-cli.jar + * $HOME/src/zxing/core/core.jar + * + * Build with: + * javac -d bin/classes -cp bin/classes:... \ + * host/org/ietfng/ns/android/vcpass/VCTestVocGen.java + * + */ + +package org.ietfng.ns.android.vcpass; + +import java.io.FileWriter; +import java.security.SecureRandom; +import java.security.Provider; +import java.security.Security; +import javax.crypto.SecretKey; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.MultiFormatWriter; +import com.google.zxing.common.ByteMatrix; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.PosixParser; +import org.apache.commons.codec.binary.Base64; + +public final class VCTestVocGen { + static final private int SEED_SIZE = 16; + + private static final int QR_SIZEX = 400; + private static final int QR_SIZEY = 400; + + static final private Options cliopts = new Options(); + static final private String OPT_SS_HELP = "h"; + static final private String OPT_SS_SECRET = "S"; + static final private String OPT_SS_VOCSEC = "V"; + static final private String OPT_SS_GENEXC = "c"; + static final private String OPT_SS_GENEXV = "v"; + + private static final int crpix = VCParameters.DISP_X + / VCParameters.GRID_X; + private static final int ccpix = VCParameters.DISP_Y + / VCParameters.GRID_Y; + + private static final void + printPBMHeader(FileWriter f, int v, int x, int y) + throws java.io.IOException + { + StringBuilder sb = new StringBuilder(); + sb.append("P"); + sb.append(v); + sb.append(" "); + sb.append(x); + sb.append(" "); + sb.append(y); + sb.append("\n"); + f.write(sb.toString(), 0, sb.length()); + } + + static { + cliopts.addOption(OPT_SS_HELP, "help", false, "Show this help"); + cliopts.addOption(OPT_SS_SECRET, "secretseed", true, + "Secret seed (for development)"); + cliopts.addOption(OPT_SS_SECRET, "slideseed", true, + "Slide seed (for development)"); + cliopts.addOption(OPT_SS_VOCSEC, "vocseed", true, + "Vocabulary seed (for development)"); + cliopts.addOption(OPT_SS_GENEXC, "chalfile", true, + "Example challenge file name"); + cliopts.addOption(OPT_SS_GENEXV, "vocfile", true, + "Example vocabulary file name"); + } + + public static void main(String[] args) throws Exception { + CommandLineParser parser = new PosixParser(); + CommandLine cmd = parser.parse(cliopts, args); + + if(cmd.hasOption(OPT_SS_HELP)) { + HelpFormatter formatter = new HelpFormatter(); + formatter.printHelp( "VCSlideGen" , cliopts ); + return; + } + + Security.addProvider(VCParameters.CSPROV); + + char[] useed; + if(cmd.hasOption(OPT_SS_SECRET)) { + useed = cmd.getOptionValue(OPT_SS_SECRET).toCharArray(); + } else { + // XXX + useed = "foo".toCharArray(); + } + + char[] vseed; + if(cmd.hasOption(OPT_SS_VOCSEC)) { + vseed = cmd.getOptionValue(OPT_SS_VOCSEC).toCharArray(); + } else { + // XXX + vseed = "bar".toCharArray(); + } + + if(cmd.hasOption(OPT_SS_GENEXV)) { + Integer[][] vocab = new Integer[VCParameters.VCVOC_SIZE][]; + Integer[][] vslide = new Integer[VCParameters.VCVOC_SIZE][]; + + { + Integer[][] slide = VCGenerator.generateSlide( useed, null ); + for(int i = 0; i < vslide.length; i++) { + vslide[i] = slide[0]; + } + } + + for(int i = 0; i < vocab.length; i++) { + int[] plain = new int[VCParameters.GRID_X + *VCParameters.GRID_Y]; + plain[0] = i; + + Integer[][] vocabi = VCGenerator.generateChallenge( + vseed, useed, plain, null + ); + + vocab[i] = vocabi[0]; + } + + FileWriter vout = new FileWriter( + cmd.getOptionValue(OPT_SS_GENEXV) + ); + printPBMHeader(vout, 1, VCParameters.DISP_X, + VCParameters.DISP_Y); + + /* XXX */ + int[][] spixels = VCGenerator.vcArrayToPixels(vslide); + int[][] vpixels = VCGenerator.vcArrayToPixels(vocab); + + for(int i = crpix-1; i < VCParameters.DISP_X-1; i += crpix){ + for(int r = 0; r < vpixels.length; r++) { + vpixels[i][r] = VCParameters.black; + vpixels[i+1][r] = VCParameters.black; + vpixels[r][i] = VCParameters.black; + vpixels[r][i+1] = VCParameters.black; + }} + + for(int r = 0; r < vpixels.length; r++) { + for(int c = 0; c < vpixels[r].length; c++) { + if(spixels[r][c] == VCParameters.black) { + vout.write('1'); + } else { + vout.write(vpixels[r][c] == VCParameters.white ? + '0' : '1'); + } + } + vout.write('\n'); + } + vout.flush(); + vout.close(); + } + + if(cmd.hasOption(OPT_SS_GENEXC)) { + int[] plain = new int[VCParameters.GRID_X + *VCParameters.GRID_Y]; + for(int i = 0; i < plain.length; i++ ){ + plain[i] = (i*7+8) % VCParameters.VCVOC_SIZE; + } + FileWriter vout = new FileWriter( + cmd.getOptionValue(OPT_SS_GENEXC) + ); + printPBMHeader(vout, 1, VCParameters.DISP_X, + VCParameters.DISP_Y); + + Integer[][] vocab = VCGenerator.generateChallenge( + vseed, useed, plain, null + ); + int[][] vpixels = VCGenerator.vcArrayToPixels(vocab); + + Integer[][] slide = VCGenerator.generateSlide( useed, null ); + int[][] spixels = VCGenerator.vcArrayToPixels(slide); + + for(int i = crpix-1; i < VCParameters.DISP_X-1; i += crpix){ + for(int r = 0; r < vpixels.length; r++) { + vpixels[i][r] = VCParameters.black; + vpixels[i+1][r] = VCParameters.black; + vpixels[r][i] = VCParameters.black; + vpixels[r][i+1] = VCParameters.black; + }} + + for(int r = 0; r < vpixels.length; r++) { + for(int c = 0; c < vpixels[r].length; c++) { + if(spixels[r][c] == VCParameters.black) { + vout.write('1'); + } else { + vout.write(vpixels[r][c] == VCParameters.white ? + '0' : '1'); + } + } + vout.write('\n'); + } + vout.flush(); + vout.close(); + } + } +} diff --git a/res/drawable-hdpi/icon.png b/res/drawable-hdpi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8074c4c571b8cd19e27f4ee5545df367420686d7 GIT binary patch literal 4147 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 literal 0 HcmV?d00001 diff --git a/res/drawable-ldpi/icon.png b/res/drawable-ldpi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1095584ec21f71cd0afc9e0993aa2209671b590c GIT binary patch literal 1723 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 + + + + diff --git a/res/layout/vcpact.xml b/res/layout/vcpact.xml new file mode 100644 index 0000000..14ab14e --- /dev/null +++ b/res/layout/vcpact.xml @@ -0,0 +1,30 @@ + + + +