intermediate state, nothing really working yet

This commit is contained in:
Vincent Breitmoser
2015-01-12 13:17:18 +01:00
parent 6570483fab
commit 5faeb5f5f0
20 changed files with 1570 additions and 0 deletions

View File

@@ -0,0 +1,157 @@
package org.sufficientlysecure.keychain.pgp.affirmation;
import org.spongycastle.bcpg.UserAttributeSubpacket;
import org.spongycastle.util.Strings;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.util.Log;
import java.net.URI;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
public class Affirmation {
protected byte[] mData;
public final long mNonce;
public final URI mSubUri;
final Set<String> mFlags;
final HashMap<String,String> mParams;
protected Affirmation(byte[] data, long nonce, Set<String> flags,
HashMap<String,String> params, URI subUri) {
mData = data;
mNonce = nonce;
mFlags = flags;
mParams = params;
mSubUri = subUri;
}
Affirmation(long nonce, Set<String> flags,
HashMap<String,String> params, URI subUri) {
this(null, nonce, flags, params, subUri);
}
public byte[] encode() {
if (mData != null) {
return mData;
}
StringBuilder b = new StringBuilder();
b.append("pgpid:");
// add flags
if (mFlags != null) {
boolean first = true;
for (String flag : mFlags) {
if (!first) {
b.append(";");
}
first = false;
b.append(flag);
}
}
// add parameters
if (mParams != null) {
boolean first = true;
Iterator<Entry<String, String>> it = mParams.entrySet().iterator();
while (it.hasNext()) {
if (!first) {
b.append(";");
}
first = false;
Entry<String, String> entry = it.next();
b.append(entry.getKey()).append("=").append(entry.getValue());
}
}
b.append("@");
b.append(mSubUri);
byte[] data = Strings.toUTF8ByteArray(b.toString());
byte[] result = new byte[data.length+4];
result[0] = (byte) (mNonce >> 24 & 255);
result[1] = (byte) (mNonce >> 16 & 255);
result[2] = (byte) (mNonce >> 8 & 255);
result[3] = (byte) (mNonce & 255);
System.arraycopy(data, 0, result, 4, result.length);
return result;
}
/** This method parses an affirmation from a UserAttributeSubpacket, or returns null if the
* subpacket can not be parsed as a valid affirmation.
*/
public static Affirmation parseAffirmation(UserAttributeSubpacket subpacket) {
if (subpacket.getType() != 100) {
return null;
}
byte[] data = subpacket.getData();
long nonce = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
try {
return parseUri(nonce, Strings.fromUTF8ByteArray(Arrays.copyOfRange(data, 4, data.length)));
} catch (IllegalArgumentException e) {
Log.e(Constants.TAG, "error parsing uri in (suspected) affirmation packet");
return null;
}
}
public static Affirmation generateForUri(String uri) {
return parseUri(generateNonce(), uri);
}
protected static Affirmation parseUri (long nonce, String uriString) {
URI uri = URI.create(uriString);
if ("pgpid".equals(uri.getScheme())) {
Log.e(Constants.TAG, "unknown uri scheme in (suspected) affirmation packet");
return null;
}
if (!uri.isOpaque()) {
Log.e(Constants.TAG, "non-opaque uri in (suspected) affirmation packet");
return null;
}
String specific = uri.getSchemeSpecificPart();
if (!specific.contains("@")) {
Log.e(Constants.TAG, "unknown uri scheme in affirmation packet");
return null;
}
String[] pieces = specific.split("@", 2);
URI subUri = URI.create(pieces[1]);
Set<String> flags = new HashSet<String>();
HashMap<String,String> params = new HashMap<String,String>();
{
String[] rawParams = pieces[0].split(";");
for (String param : rawParams) {
String[] p = param.split("=", 2);
if (p.length == 1) {
flags.add(param);
} else {
params.put(p[0], p[1]);
}
}
}
return new Affirmation(null, nonce, flags, params, subUri);
}
public static long generateNonce() {
return 1234567890L; // new SecureRandom().nextLong();
}
}

View File

@@ -0,0 +1,43 @@
package org.sufficientlysecure.keychain.pgp.affirmation;
import org.sufficientlysecure.keychain.pgp.affirmation.resources.GenericHttpsResource;
import org.sufficientlysecure.keychain.pgp.affirmation.resources.UnknownResource;
import java.net.URI;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Set;
public abstract class AffirmationResource {
protected final URI mUri;
protected final Set<String> mFlags;
protected final HashMap<String,String> mParams;
protected AffirmationResource(Set<String> flags, HashMap<String,String> params, URI uri) {
mFlags = flags;
mParams = params;
mUri = uri;
}
public abstract boolean verify();
public static AffirmationResource findResourceType
(Set<String> flags, HashMap<String,String> params, URI uri) {
AffirmationResource res;
res = GenericHttpsResource.create(flags, params, uri);
if (res != null) {
return res;
}
return new UnknownResource(flags, params, uri);
}
public static long generateNonce() {
return 1234567890L; // new SecureRandom().nextLong();
}
}

View File

@@ -0,0 +1,4 @@
package org.sufficientlysecure.keychain.pgp.affirmation.resources;
public class DnsResouce {
}

View File

@@ -0,0 +1,130 @@
package org.sufficientlysecure.keychain.pgp.affirmation.resources;
import android.content.Context;
import com.textuality.keybase.lib.Search;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.affirmation.AffirmationResource;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import javax.net.ssl.HttpsURLConnection;
public class GenericHttpsResource extends AffirmationResource {
GenericHttpsResource(Set<String> flags, HashMap<String,String> params, URI uri) {
super(flags, params, uri);
}
@Override
public boolean verify() {
return false;
}
public static String generate (byte[] fingerprint, String uri) {
long nonce = generateNonce();
StringBuilder b = new StringBuilder();
b.append("---\r\n");
b.append("fingerprint=");
b.append(KeyFormattingUtils.convertFingerprintToHex(fingerprint));
b.append('\r').append('\n');
b.append("nonce=");
b.append(nonce);
b.append('\r').append('\n');
if (uri != null) {
b.append("uri=");
b.append(uri);
b.append('\r').append('\n');
}
b.append("---\r\n");
return b.toString();
}
public DecryptVerifyResult verify
(Context context, ProviderHelper providerHelper, Progressable progress)
throws IOException {
byte[] data = fetchResource(mUri).getBytes();
InputData input = new InputData(new ByteArrayInputStream(data), data.length);
ByteArrayOutputStream out = new ByteArrayOutputStream();
PgpDecryptVerify.Builder b =
new PgpDecryptVerify.Builder(context, providerHelper, progress, input, out);
PgpDecryptVerify op = b.build();
Log.d(Constants.TAG, new String(out.toByteArray()));
return op.execute();
}
protected static String fetchResource (URI uri) throws IOException {
try {
HttpsURLConnection conn = null;
URL url = uri.toURL();
int status = 0;
int redirects = 0;
while (redirects < 5) {
conn = (HttpsURLConnection) url.openConnection();
conn.addRequestProperty("User-Agent", "OpenKeychain");
conn.setConnectTimeout(5000);
conn.setReadTimeout(25000);
conn.connect();
status = conn.getResponseCode();
if (status == 301) {
redirects++;
url = new URL(conn.getHeaderFields().get("Location").get(0));
} else {
break;
}
}
if (status >= 200 && status < 300) {
return Search.snarf(conn.getInputStream());
} else {
throw new IOException("Fetch failed, status " + status + ": " + Search.snarf(conn.getErrorStream()));
}
} catch (MalformedURLException e) {
throw new IOException(e);
}
}
public static GenericHttpsResource createNew (URI uri) {
HashSet<String> flags = new HashSet<String>();
flags.add("generic");
HashMap<String,String> params = new HashMap<String,String>();
return create(flags, params, uri);
}
public static GenericHttpsResource create(Set<String> flags, HashMap<String,String> params, URI uri) {
if ( ! ("https".equals(uri.getScheme())
&& flags != null && flags.size() == 1 && flags.contains("generic")
&& (params == null || params.isEmpty()))) {
return null;
}
return new GenericHttpsResource(flags, params, uri);
}
}

View File

@@ -0,0 +1,4 @@
package org.sufficientlysecure.keychain.pgp.affirmation.resources;
public class TwitterResource {
}

View File

@@ -0,0 +1,20 @@
package org.sufficientlysecure.keychain.pgp.affirmation.resources;
import org.sufficientlysecure.keychain.pgp.affirmation.AffirmationResource;
import java.net.URI;
import java.util.HashMap;
import java.util.Set;
public class UnknownResource extends AffirmationResource {
public UnknownResource(Set<String> flags, HashMap<String,String> params, URI uri) {
super(flags, params, uri);
}
@Override
public boolean verify() {
return false;
}
}