even more intermediate result
This commit is contained in:
@@ -1,11 +1,15 @@
|
||||
package org.sufficientlysecure.keychain.pgp.affirmation;
|
||||
|
||||
import org.spongycastle.bcpg.UserAttributeSubpacket;
|
||||
import org.spongycastle.util.BigIntegers;
|
||||
import org.spongycastle.util.Strings;
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.net.URI;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -16,13 +20,17 @@ import java.util.Set;
|
||||
public class Affirmation {
|
||||
|
||||
protected byte[] mData;
|
||||
public final long mNonce;
|
||||
public final String mNonce;
|
||||
public final URI mSubUri;
|
||||
final Set<String> mFlags;
|
||||
final HashMap<String,String> mParams;
|
||||
|
||||
protected Affirmation(byte[] data, long nonce, Set<String> flags,
|
||||
protected Affirmation(byte[] data, String nonce, Set<String> flags,
|
||||
HashMap<String,String> params, URI subUri) {
|
||||
if ( ! nonce.matches("[0-9a-zA-Z]+")) {
|
||||
throw new AssertionError("bug: nonce must be hexstring!");
|
||||
}
|
||||
|
||||
mData = data;
|
||||
mNonce = nonce;
|
||||
mFlags = flags;
|
||||
@@ -30,7 +38,7 @@ public class Affirmation {
|
||||
mSubUri = subUri;
|
||||
}
|
||||
|
||||
Affirmation(long nonce, Set<String> flags,
|
||||
Affirmation(String nonce, Set<String> flags,
|
||||
HashMap<String,String> params, URI subUri) {
|
||||
this(null, nonce, flags, params, subUri);
|
||||
}
|
||||
@@ -72,15 +80,12 @@ public class Affirmation {
|
||||
b.append("@");
|
||||
b.append(mSubUri);
|
||||
|
||||
byte[] nonceBytes = Hex.decode(mNonce);
|
||||
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);
|
||||
byte[] result = new byte[data.length+12];
|
||||
System.arraycopy(nonceBytes, 0, result, 0, 12);
|
||||
System.arraycopy(data, 0, result, 12, result.length);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -94,11 +99,10 @@ public class Affirmation {
|
||||
}
|
||||
|
||||
byte[] data = subpacket.getData();
|
||||
|
||||
long nonce = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
|
||||
String nonce = Hex.toHexString(data, 0, 12);
|
||||
|
||||
try {
|
||||
return parseUri(nonce, Strings.fromUTF8ByteArray(Arrays.copyOfRange(data, 4, data.length)));
|
||||
return parseUri(nonce, Strings.fromUTF8ByteArray(Arrays.copyOfRange(data, 12, data.length)));
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.e(Constants.TAG, "error parsing uri in (suspected) affirmation packet");
|
||||
@@ -106,11 +110,7 @@ public class Affirmation {
|
||||
}
|
||||
}
|
||||
|
||||
public static Affirmation generateForUri(String uri) {
|
||||
return parseUri(generateNonce(), uri);
|
||||
}
|
||||
|
||||
protected static Affirmation parseUri (long nonce, String uriString) {
|
||||
protected static Affirmation parseUri (String nonce, String uriString) {
|
||||
URI uri = URI.create(uriString);
|
||||
|
||||
if ("pgpid".equals(uri.getScheme())) {
|
||||
@@ -146,12 +146,18 @@ public class Affirmation {
|
||||
}
|
||||
}
|
||||
|
||||
return new Affirmation(null, nonce, flags, params, subUri);
|
||||
return new Affirmation(nonce, flags, params, subUri);
|
||||
|
||||
}
|
||||
|
||||
public static long generateNonce() {
|
||||
return 1234567890L; // new SecureRandom().nextLong();
|
||||
public static String generateNonce() {
|
||||
// TODO make this actually random
|
||||
// byte[] data = new byte[96];
|
||||
// new SecureRandom().nextBytes(data);
|
||||
// return Hex.toHexString(data);
|
||||
|
||||
// debug for now
|
||||
return "0123456789ABCDEF01234567";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
package org.sufficientlysecure.keychain.pgp.affirmation;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
|
||||
import org.sufficientlysecure.keychain.pgp.affirmation.resources.GenericHttpsResource;
|
||||
import org.sufficientlysecure.keychain.pgp.affirmation.resources.UnknownResource;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.net.URI;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public abstract class AffirmationResource {
|
||||
|
||||
@@ -14,13 +23,73 @@ public abstract class AffirmationResource {
|
||||
protected final Set<String> mFlags;
|
||||
protected final HashMap<String,String> mParams;
|
||||
|
||||
static Pattern magicPattern =
|
||||
Pattern.compile("\\[Verifying my PGP key: pgpid\\+cookie:([a-zA-Z0-9]+)#([a-zA-Z0-9]+)\\]");
|
||||
|
||||
protected AffirmationResource(Set<String> flags, HashMap<String,String> params, URI uri) {
|
||||
mFlags = flags;
|
||||
mParams = params;
|
||||
mUri = uri;
|
||||
}
|
||||
|
||||
public abstract boolean verify();
|
||||
public static String generate (Context context, byte[] fingerprint, String nonce) {
|
||||
|
||||
return "[Verifying my PGP key: pgpid+cookie:"
|
||||
+ KeyFormattingUtils.convertFingerprintToHex(fingerprint) + "#" + nonce + "]";
|
||||
|
||||
}
|
||||
|
||||
public LinkedVerifyResult verify(byte[] fingerprint, String nonce) {
|
||||
|
||||
OperationLog log = new OperationLog();
|
||||
log.add(LogType.MSG_LV, 0);
|
||||
|
||||
// Try to fetch resource. Logs for itself
|
||||
String res = fetchResource(log, 1);
|
||||
if (res == null) {
|
||||
// if this is null, an error was recorded in fetchResource above
|
||||
return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log);
|
||||
}
|
||||
|
||||
Log.d(Constants.TAG, res);
|
||||
|
||||
return verifyString(log, 1, res, nonce, fingerprint);
|
||||
|
||||
}
|
||||
|
||||
protected abstract String fetchResource (OperationLog log, int indent);
|
||||
|
||||
protected LinkedVerifyResult verifyString (OperationLog log, int indent,
|
||||
String res,
|
||||
String nonce, byte[] fingerprint) {
|
||||
|
||||
log.add(LogType.MSG_LV_MATCH, indent);
|
||||
Matcher match = magicPattern.matcher(res);
|
||||
if (!match.find()) {
|
||||
log.add(LogType.MSG_LV_MATCH_ERROR, 2);
|
||||
return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log);
|
||||
}
|
||||
|
||||
String candidateFp = match.group(1);
|
||||
String nonceCandidate = match.group(2);
|
||||
|
||||
String fp = KeyFormattingUtils.convertFingerprintToHex(fingerprint);
|
||||
|
||||
if (!fp.equals(candidateFp)) {
|
||||
log.add(LogType.MSG_LV_FP_ERROR, indent);
|
||||
return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log);
|
||||
}
|
||||
log.add(LogType.MSG_LV_FP_OK, indent);
|
||||
|
||||
if (!nonce.equals(nonceCandidate)) {
|
||||
log.add(LogType.MSG_LV_NONCE_ERROR, indent);
|
||||
return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log);
|
||||
}
|
||||
|
||||
log.add(LogType.MSG_LV_NONCE_OK, indent);
|
||||
return new LinkedVerifyResult(LinkedVerifyResult.RESULT_OK, log);
|
||||
|
||||
}
|
||||
|
||||
public static AffirmationResource findResourceType
|
||||
(Set<String> flags, HashMap<String,String> params, URI uri) {
|
||||
@@ -36,8 +105,4 @@ public abstract class AffirmationResource {
|
||||
|
||||
}
|
||||
|
||||
public static long generateNonce() {
|
||||
return 1234567890L; // new SecureRandom().nextLong();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,47 @@
|
||||
package org.sufficientlysecure.keychain.pgp.affirmation.resources;
|
||||
|
||||
public class DnsResouce {
|
||||
import android.content.Context;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
|
||||
import org.sufficientlysecure.keychain.pgp.affirmation.AffirmationResource;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
import de.measite.minidns.Client;
|
||||
import de.measite.minidns.DNSMessage;
|
||||
import de.measite.minidns.Question;
|
||||
import de.measite.minidns.Record;
|
||||
import de.measite.minidns.Record.TYPE;
|
||||
import de.measite.minidns.record.TXT;
|
||||
|
||||
public class DnsResouce extends AffirmationResource {
|
||||
|
||||
DnsResouce(Set<String> flags, HashMap<String,String> params, URI uri) {
|
||||
super(flags, params, uri);
|
||||
}
|
||||
|
||||
public static String generate (Context context, byte[] fingerprint, String nonce) {
|
||||
|
||||
return "pgpid+cookie:"
|
||||
+ KeyFormattingUtils.convertFingerprintToHex(fingerprint) + ";" + nonce + "";
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String fetchResource (OperationLog log, int indent) {
|
||||
|
||||
Client c = new Client();
|
||||
DNSMessage msg = c.query(new Question("mugenguild.com", TYPE.TXT));
|
||||
Record aw = msg.getAnswers()[0];
|
||||
TXT txt = (TXT) aw.getPayload();
|
||||
Log.d(Constants.TAG, txt.getText());
|
||||
return txt.getText();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,9 +5,14 @@ import android.content.Context;
|
||||
import com.textuality.keybase.lib.Search;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
||||
import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
|
||||
import org.sufficientlysecure.keychain.pgp.Progressable;
|
||||
import org.sufficientlysecure.keychain.pgp.affirmation.Affirmation;
|
||||
import org.sufficientlysecure.keychain.pgp.affirmation.AffirmationResource;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
@@ -17,7 +22,6 @@ 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;
|
||||
@@ -33,58 +37,26 @@ public class GenericHttpsResource extends AffirmationResource {
|
||||
super(flags, params, uri);
|
||||
}
|
||||
|
||||
public static String generateText (Context context, byte[] fingerprint, String nonce) {
|
||||
String cookie = AffirmationResource.generate(context, fingerprint, nonce);
|
||||
|
||||
return String.format(context.getResources().getString(R.string.linked_id_generic_text),
|
||||
cookie, "0x" + KeyFormattingUtils.convertFingerprintToHex(fingerprint).substring(24));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify() {
|
||||
return false;
|
||||
}
|
||||
protected String fetchResource (OperationLog log, int indent) {
|
||||
|
||||
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 {
|
||||
log.add(LogType.MSG_LV_FETCH, indent, mUri.toString());
|
||||
indent += 1;
|
||||
|
||||
try {
|
||||
|
||||
HttpsURLConnection conn = null;
|
||||
URL url = uri.toURL();
|
||||
URL url = mUri.toURL();
|
||||
int status = 0;
|
||||
int redirects = 0;
|
||||
|
||||
while (redirects < 5) {
|
||||
conn = (HttpsURLConnection) url.openConnection();
|
||||
conn.addRequestProperty("User-Agent", "OpenKeychain");
|
||||
@@ -95,18 +67,28 @@ public class GenericHttpsResource extends AffirmationResource {
|
||||
if (status == 301) {
|
||||
redirects++;
|
||||
url = new URL(conn.getHeaderFields().get("Location").get(0));
|
||||
log.add(LogType.MSG_LV_FETCH_REDIR, indent, url.toString());
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (status >= 200 && status < 300) {
|
||||
log.add(LogType.MSG_LV_FETCH_OK, indent, Integer.toString(status));
|
||||
return Search.snarf(conn.getInputStream());
|
||||
} else {
|
||||
throw new IOException("Fetch failed, status " + status + ": " + Search.snarf(conn.getErrorStream()));
|
||||
// log verbose output to logcat
|
||||
Log.e(Constants.TAG, Search.snarf(conn.getErrorStream()));
|
||||
log.add(LogType.MSG_LV_FETCH_ERROR, indent, Integer.toString(status));
|
||||
return null;
|
||||
}
|
||||
|
||||
} catch (MalformedURLException e) {
|
||||
throw new IOException(e);
|
||||
log.add(LogType.MSG_LV_FETCH_ERROR_URL, indent);
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
log.add(LogType.MSG_LV_FETCH_ERROR_IO, indent);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,119 @@
|
||||
package org.sufficientlysecure.keychain.pgp.affirmation.resources;
|
||||
|
||||
public class TwitterResource {
|
||||
import android.util.Base64;
|
||||
import android.util.JsonReader;
|
||||
|
||||
import com.textuality.keybase.lib.JWalk;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.params.BasicHttpParams;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
|
||||
import org.sufficientlysecure.keychain.pgp.affirmation.AffirmationResource;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
public class TwitterResource extends AffirmationResource {
|
||||
|
||||
TwitterResource(Set<String> flags, HashMap<String,String> params, URI uri) {
|
||||
super(flags, params, uri);
|
||||
}
|
||||
|
||||
private String getTwitterStream(String screenName) {
|
||||
String results = null;
|
||||
|
||||
// Step 1: Encode consumer key and secret
|
||||
try {
|
||||
// URL encode the consumer key and secret
|
||||
String urlApiKey = URLEncoder.encode("6IhPnWbYxASAoAzH2QaUtHD0J", "UTF-8");
|
||||
String urlApiSecret = URLEncoder.encode("L0GnuiOnapWbSBbQtLIqtpeS5BTtvh06dmoMoKQfHQS8UwHuWm", "UTF-8");
|
||||
|
||||
// Concatenate the encoded consumer key, a colon character, and the
|
||||
// encoded consumer secret
|
||||
String combined = urlApiKey + ":" + urlApiSecret;
|
||||
|
||||
// Base64 encode the string
|
||||
String base64Encoded = Base64.encodeToString(combined.getBytes(), Base64.NO_WRAP);
|
||||
|
||||
// Step 2: Obtain a bearer token
|
||||
HttpPost httpPost = new HttpPost("https://api.twitter.com/oauth2/token");
|
||||
httpPost.setHeader("Authorization", "Basic " + base64Encoded);
|
||||
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
|
||||
httpPost.setEntity(new StringEntity("grant_type=client_credentials"));
|
||||
JSONObject rawAuthorization = new JSONObject(getResponseBody(httpPost));
|
||||
String auth = JWalk.getString(rawAuthorization, "access_token");
|
||||
|
||||
// Applications should verify that the value associated with the
|
||||
// token_type key of the returned object is bearer
|
||||
if (auth != null && JWalk.getString(rawAuthorization, "token_type").equals("bearer")) {
|
||||
|
||||
// Step 3: Authenticate API requests with bearer token
|
||||
HttpGet httpGet =
|
||||
new HttpGet("https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=" + screenName);
|
||||
|
||||
// construct a normal HTTPS request and include an Authorization
|
||||
// header with the value of Bearer <>
|
||||
httpGet.setHeader("Authorization", "Bearer " + auth);
|
||||
httpGet.setHeader("Content-Type", "application/json");
|
||||
// update the results with the body of the response
|
||||
results = getResponseBody(httpGet);
|
||||
}
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
} catch (JSONException ex) {
|
||||
} catch (IllegalStateException ex1) {
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static String getResponseBody(HttpRequestBase request) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
try {
|
||||
|
||||
DefaultHttpClient httpClient = new DefaultHttpClient(new BasicHttpParams());
|
||||
HttpResponse response = httpClient.execute(request);
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
String reason = response.getStatusLine().getReasonPhrase();
|
||||
|
||||
if (statusCode == 200) {
|
||||
|
||||
HttpEntity entity = response.getEntity();
|
||||
InputStream inputStream = entity.getContent();
|
||||
|
||||
BufferedReader bReader = new BufferedReader(
|
||||
new InputStreamReader(inputStream, "UTF-8"), 8);
|
||||
String line = null;
|
||||
while ((line = bReader.readLine()) != null) {
|
||||
sb.append(line);
|
||||
}
|
||||
} else {
|
||||
sb.append(reason);
|
||||
}
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
} catch (ClientProtocolException ex1) {
|
||||
} catch (IOException ex2) {
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String fetchResource(OperationLog log, int indent) {
|
||||
return getTwitterStream("Valodim");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package org.sufficientlysecure.keychain.pgp.affirmation.resources;
|
||||
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
|
||||
import org.sufficientlysecure.keychain.pgp.affirmation.AffirmationResource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
@@ -13,8 +15,8 @@ public class UnknownResource extends AffirmationResource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify() {
|
||||
return false;
|
||||
protected String fetchResource(OperationLog log, int indent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user