Rename folder structure from OpenPGP Keychain to OpenKeychain
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.util;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import org.spongycastle.bcpg.HashAlgorithmTags;
|
||||
import org.spongycastle.openpgp.PGPEncryptedData;
|
||||
import org.sufficientlysecure.keychain.Id;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@SuppressLint("UseSparseArrays")
|
||||
public class AlgorithmNames {
|
||||
Activity mActivity;
|
||||
|
||||
HashMap<Integer, String> mEncryptionNames = new HashMap<Integer, String>();
|
||||
HashMap<Integer, String> mHashNames = new HashMap<Integer, String>();
|
||||
HashMap<Integer, String> mCompressionNames = new HashMap<Integer, String>();
|
||||
|
||||
public AlgorithmNames(Activity context) {
|
||||
super();
|
||||
this.mActivity = context;
|
||||
|
||||
mEncryptionNames.put(PGPEncryptedData.AES_128, "AES-128");
|
||||
mEncryptionNames.put(PGPEncryptedData.AES_192, "AES-192");
|
||||
mEncryptionNames.put(PGPEncryptedData.AES_256, "AES-256");
|
||||
mEncryptionNames.put(PGPEncryptedData.BLOWFISH, "Blowfish");
|
||||
mEncryptionNames.put(PGPEncryptedData.TWOFISH, "Twofish");
|
||||
mEncryptionNames.put(PGPEncryptedData.CAST5, "CAST5");
|
||||
mEncryptionNames.put(PGPEncryptedData.DES, "DES");
|
||||
mEncryptionNames.put(PGPEncryptedData.TRIPLE_DES, "Triple DES");
|
||||
mEncryptionNames.put(PGPEncryptedData.IDEA, "IDEA");
|
||||
|
||||
mHashNames.put(HashAlgorithmTags.MD5, "MD5");
|
||||
mHashNames.put(HashAlgorithmTags.RIPEMD160, "RIPEMD-160");
|
||||
mHashNames.put(HashAlgorithmTags.SHA1, "SHA-1");
|
||||
mHashNames.put(HashAlgorithmTags.SHA224, "SHA-224");
|
||||
mHashNames.put(HashAlgorithmTags.SHA256, "SHA-256");
|
||||
mHashNames.put(HashAlgorithmTags.SHA384, "SHA-384");
|
||||
mHashNames.put(HashAlgorithmTags.SHA512, "SHA-512");
|
||||
|
||||
mCompressionNames.put(Id.choice.compression.none, mActivity.getString(R.string.choice_none)
|
||||
+ " (" + mActivity.getString(R.string.compression_fast) + ")");
|
||||
mCompressionNames.put(Id.choice.compression.zip,
|
||||
"ZIP (" + mActivity.getString(R.string.compression_fast) + ")");
|
||||
mCompressionNames.put(Id.choice.compression.zlib,
|
||||
"ZLIB (" + mActivity.getString(R.string.compression_fast) + ")");
|
||||
mCompressionNames.put(Id.choice.compression.bzip2,
|
||||
"BZIP2 (" + mActivity.getString(R.string.compression_very_slow) + ")");
|
||||
}
|
||||
|
||||
public HashMap<Integer, String> getEncryptionNames() {
|
||||
return mEncryptionNames;
|
||||
}
|
||||
|
||||
public void setEncryptionNames(HashMap<Integer, String> encryptionNames) {
|
||||
this.mEncryptionNames = encryptionNames;
|
||||
}
|
||||
|
||||
public HashMap<Integer, String> getHashNames() {
|
||||
return mHashNames;
|
||||
}
|
||||
|
||||
public void setHashNames(HashMap<Integer, String> hashNames) {
|
||||
this.mHashNames = hashNames;
|
||||
}
|
||||
|
||||
public HashMap<Integer, String> getCompressionNames() {
|
||||
return mCompressionNames;
|
||||
}
|
||||
|
||||
public void setCompressionNames(HashMap<Integer, String> compressionNames) {
|
||||
this.mCompressionNames = compressionNames;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
|
||||
*
|
||||
* 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 org.sufficientlysecure.keychain.util;
|
||||
|
||||
public class Choice {
|
||||
private String mName;
|
||||
private int mId;
|
||||
|
||||
public Choice() {
|
||||
mId = -1;
|
||||
mName = "";
|
||||
}
|
||||
|
||||
public Choice(int id, String name) {
|
||||
mId = id;
|
||||
mName = name;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
* Copyright (C) 2011 Thialfihar <thi@thialfihar.org>
|
||||
* Copyright (C) 2011 Senecaso
|
||||
*
|
||||
* 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 org.sufficientlysecure.keychain.util;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.InetAddress;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class HkpKeyServer extends KeyServer {
|
||||
private static class HttpError extends Exception {
|
||||
private static final long serialVersionUID = 1718783705229428893L;
|
||||
private int mCode;
|
||||
private String mData;
|
||||
|
||||
public HttpError(int code, String data) {
|
||||
super("" + code + ": " + data);
|
||||
mCode = code;
|
||||
mData = data;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return mCode;
|
||||
}
|
||||
|
||||
public String getData() {
|
||||
return mData;
|
||||
}
|
||||
}
|
||||
|
||||
private String mHost;
|
||||
private short mPort;
|
||||
|
||||
/**
|
||||
* pub:%keyid%:%algo%:%keylen%:%creationdate%:%expirationdate%:%flags%
|
||||
* <ul>
|
||||
* <li>%<b>keyid</b>% = this is either the fingerprint or the key ID of the key.
|
||||
* Either the 16-digit or 8-digit key IDs are acceptable, but obviously the fingerprint is best.
|
||||
* </li>
|
||||
* <li>%<b>algo</b>% = the algorithm number, (i.e. 1==RSA, 17==DSA, etc).
|
||||
* See <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a></li>
|
||||
* <li>%<b>keylen</b>% = the key length (i.e. 1024, 2048, 4096, etc.)</li>
|
||||
* <li>%<b>creationdate</b>% = creation date of the key in standard
|
||||
* <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a> form (i.e. number of
|
||||
* seconds since 1/1/1970 UTC time)</li>
|
||||
* <li>%<b>expirationdate</b>% = expiration date of the key in standard
|
||||
* <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a> form (i.e. number of
|
||||
* seconds since 1/1/1970 UTC time)</li>
|
||||
* <li>%<b>flags</b>% = letter codes to indicate details of the key, if any. Flags may be in any
|
||||
* order. The meaning of "disabled" is implementation-specific. Note that individual flags may
|
||||
* be unimplemented, so the absence of a given flag does not necessarily mean the absence of the
|
||||
* detail.
|
||||
* <ul>
|
||||
* <li>r == revoked</li>
|
||||
* <li>d == disabled</li>
|
||||
* <li>e == expired</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @see <a href="http://tools.ietf.org/html/draft-shaw-openpgp-hkp-00#section-5.2">
|
||||
* 5.2. Machine Readable Indexes</a>
|
||||
* in Internet-Draft OpenPGP HTTP Keyserver Protocol Document
|
||||
*/
|
||||
public static final Pattern PUB_KEY_LINE = Pattern
|
||||
.compile("pub:([0-9a-fA-F]+):([0-9]+):([0-9]+):([0-9]+):([0-9]*):([rde]*)[ \n\r]*" // pub line
|
||||
+ "(uid:(.*):([0-9]+):([0-9]*):([rde]*))+", // one or more uid lines
|
||||
Pattern.CASE_INSENSITIVE);
|
||||
|
||||
/**
|
||||
* uid:%escaped uid string%:%creationdate%:%expirationdate%:%flags%
|
||||
* <ul>
|
||||
* <li>%<b>escaped uid string</b>% = the user ID string, with HTTP %-escaping for anything that
|
||||
* isn't 7-bit safe as well as for the ":" character. Any other characters may be escaped, as
|
||||
* desired.</li>
|
||||
* <li>%<b>creationdate</b>% = creation date of the key in standard
|
||||
* <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a> form (i.e. number of
|
||||
* seconds since 1/1/1970 UTC time)</li>
|
||||
* <li>%<b>expirationdate</b>% = expiration date of the key in standard
|
||||
* <a href="http://tools.ietf.org/html/rfc2440#section-9.1">RFC-2440</a> form (i.e. number of
|
||||
* seconds since 1/1/1970 UTC time)</li>
|
||||
* <li>%<b>flags</b>% = letter codes to indicate details of the key, if any. Flags may be in any
|
||||
* order. The meaning of "disabled" is implementation-specific. Note that individual flags may
|
||||
* be unimplemented, so the absence of a given flag does not necessarily mean the absence of
|
||||
* the detail.
|
||||
* <ul>
|
||||
* <li>r == revoked</li>
|
||||
* <li>d == disabled</li>
|
||||
* <li>e == expired</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* </ul>
|
||||
*/
|
||||
public static final Pattern UID_LINE = Pattern
|
||||
.compile("uid:(.*):([0-9]+):([0-9]*):([rde]*)",
|
||||
Pattern.CASE_INSENSITIVE);
|
||||
|
||||
private static final short PORT_DEFAULT = 11371;
|
||||
|
||||
/**
|
||||
* @param hostAndPort may be just
|
||||
* "<code>hostname</code>" (eg. "<code>pool.sks-keyservers.net</code>"), then it will
|
||||
* connect using {@link #PORT_DEFAULT}. However, port may be specified after colon
|
||||
* ("<code>hostname:port</code>", eg. "<code>p80.pool.sks-keyservers.net:80</code>").
|
||||
*/
|
||||
public HkpKeyServer(String hostAndPort) {
|
||||
String host = hostAndPort;
|
||||
short port = PORT_DEFAULT;
|
||||
final int colonPosition = hostAndPort.lastIndexOf(':');
|
||||
if (colonPosition > 0) {
|
||||
host = hostAndPort.substring(0, colonPosition);
|
||||
final String portStr = hostAndPort.substring(colonPosition + 1);
|
||||
port = Short.decode(portStr);
|
||||
}
|
||||
mHost = host;
|
||||
mPort = port;
|
||||
}
|
||||
|
||||
public HkpKeyServer(String host, short port) {
|
||||
mHost = host;
|
||||
mPort = port;
|
||||
}
|
||||
|
||||
private static String readAll(InputStream in, String encoding) throws IOException {
|
||||
ByteArrayOutputStream raw = new ByteArrayOutputStream();
|
||||
|
||||
byte buffer[] = new byte[1 << 16];
|
||||
int n = 0;
|
||||
while ((n = in.read(buffer)) != -1) {
|
||||
raw.write(buffer, 0, n);
|
||||
}
|
||||
|
||||
if (encoding == null) {
|
||||
encoding = "utf8";
|
||||
}
|
||||
return raw.toString(encoding);
|
||||
}
|
||||
|
||||
private String query(String request) throws QueryException, HttpError {
|
||||
InetAddress ips[];
|
||||
try {
|
||||
ips = InetAddress.getAllByName(mHost);
|
||||
} catch (UnknownHostException e) {
|
||||
throw new QueryException(e.toString());
|
||||
}
|
||||
for (int i = 0; i < ips.length; ++i) {
|
||||
try {
|
||||
String url = "http://" + ips[i].getHostAddress() + ":" + mPort + request;
|
||||
Log.d(Constants.TAG, "hkp keyserver query: " + url);
|
||||
URL realUrl = new URL(url);
|
||||
HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
|
||||
conn.setConnectTimeout(5000);
|
||||
conn.setReadTimeout(25000);
|
||||
conn.connect();
|
||||
int response = conn.getResponseCode();
|
||||
if (response >= 200 && response < 300) {
|
||||
return readAll(conn.getInputStream(), conn.getContentEncoding());
|
||||
} else {
|
||||
String data = readAll(conn.getErrorStream(), conn.getContentEncoding());
|
||||
throw new HttpError(response, data);
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
// nothing to do, try next IP
|
||||
} catch (IOException e) {
|
||||
// nothing to do, try next IP
|
||||
}
|
||||
}
|
||||
|
||||
throw new QueryException("querying server(s) for '" + mHost + "' failed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<ImportKeysListEntry> search(String query) throws QueryException, TooManyResponses,
|
||||
InsufficientQuery {
|
||||
ArrayList<ImportKeysListEntry> results = new ArrayList<ImportKeysListEntry>();
|
||||
|
||||
if (query.length() < 3) {
|
||||
throw new InsufficientQuery();
|
||||
}
|
||||
|
||||
String encodedQuery;
|
||||
try {
|
||||
encodedQuery = URLEncoder.encode(query, "utf8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return null;
|
||||
}
|
||||
String request = "/pks/lookup?op=index&options=mr&search=" + encodedQuery;
|
||||
|
||||
String data;
|
||||
try {
|
||||
data = query(request);
|
||||
} catch (HttpError e) {
|
||||
if (e.getCode() == 404) {
|
||||
return results;
|
||||
} else {
|
||||
if (e.getData().toLowerCase(Locale.US).contains("no keys found")) {
|
||||
return results;
|
||||
} else if (e.getData().toLowerCase(Locale.US).contains("too many")) {
|
||||
throw new TooManyResponses();
|
||||
} else if (e.getData().toLowerCase(Locale.US).contains("insufficient")) {
|
||||
throw new InsufficientQuery();
|
||||
}
|
||||
}
|
||||
throw new QueryException("querying server(s) for '" + mHost + "' failed");
|
||||
}
|
||||
|
||||
final Matcher matcher = PUB_KEY_LINE.matcher(data);
|
||||
while (matcher.find()) {
|
||||
final ImportKeysListEntry entry = new ImportKeysListEntry();
|
||||
|
||||
entry.setBitStrength(Integer.parseInt(matcher.group(3)));
|
||||
|
||||
final int algorithmId = Integer.decode(matcher.group(2));
|
||||
entry.setAlgorithm(ImportKeysListEntry.getAlgorithmFromId(algorithmId));
|
||||
|
||||
// group 1 contains the full fingerprint (v4) or the long key id if available
|
||||
// see http://bit.ly/1d4bxbk and http://bit.ly/1gD1wwr
|
||||
String fingerprintOrKeyId = matcher.group(1);
|
||||
if (fingerprintOrKeyId.length() > 16) {
|
||||
entry.setFingerPrintHex(fingerprintOrKeyId.toLowerCase(Locale.US));
|
||||
entry.setKeyIdHex("0x" + fingerprintOrKeyId.substring(fingerprintOrKeyId.length()
|
||||
- 16, fingerprintOrKeyId.length()));
|
||||
} else {
|
||||
// set key id only
|
||||
entry.setKeyIdHex("0x" + fingerprintOrKeyId);
|
||||
}
|
||||
|
||||
final long creationDate = Long.parseLong(matcher.group(4));
|
||||
final GregorianCalendar tmpGreg = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
|
||||
tmpGreg.setTimeInMillis(creationDate * 1000);
|
||||
entry.setDate(tmpGreg.getTime());
|
||||
|
||||
entry.setRevoked(matcher.group(6).contains("r"));
|
||||
|
||||
ArrayList<String> userIds = new ArrayList<String>();
|
||||
final String uidLines = matcher.group(7);
|
||||
final Matcher uidMatcher = UID_LINE.matcher(uidLines);
|
||||
while (uidMatcher.find()) {
|
||||
String tmp = uidMatcher.group(1).trim();
|
||||
if (tmp.contains("%")) {
|
||||
try {
|
||||
// converts Strings like "Universit%C3%A4t" to a proper encoding form "Universität".
|
||||
tmp = (URLDecoder.decode(tmp, "UTF8"));
|
||||
} catch (UnsupportedEncodingException ignored) {
|
||||
// will never happen, because "UTF8" is supported
|
||||
}
|
||||
}
|
||||
userIds.add(tmp);
|
||||
}
|
||||
entry.setUserIds(userIds);
|
||||
|
||||
results.add(entry);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String keyIdHex) throws QueryException {
|
||||
HttpClient client = new DefaultHttpClient();
|
||||
try {
|
||||
String query = "http://" + mHost + ":" + mPort +
|
||||
"/pks/lookup?op=get&options=mr&search=" + keyIdHex;
|
||||
Log.d(Constants.TAG, "hkp keyserver get: " + query);
|
||||
HttpGet get = new HttpGet(query);
|
||||
HttpResponse response = client.execute(get);
|
||||
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
|
||||
throw new QueryException("not found");
|
||||
}
|
||||
|
||||
HttpEntity entity = response.getEntity();
|
||||
InputStream is = entity.getContent();
|
||||
String data = readAll(is, EntityUtils.getContentCharSet(entity));
|
||||
Matcher matcher = PgpHelper.PGP_PUBLIC_KEY.matcher(data);
|
||||
if (matcher.find()) {
|
||||
return matcher.group(1);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// nothing to do, better luck on the next keyserver
|
||||
} finally {
|
||||
client.getConnectionManager().shutdown();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(String armoredKey) throws AddKeyException {
|
||||
HttpClient client = new DefaultHttpClient();
|
||||
try {
|
||||
String query = "http://" + mHost + ":" + mPort + "/pks/add";
|
||||
HttpPost post = new HttpPost(query);
|
||||
Log.d(Constants.TAG, "hkp keyserver add: " + query);
|
||||
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
|
||||
nameValuePairs.add(new BasicNameValuePair("keytext", armoredKey));
|
||||
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
|
||||
|
||||
HttpResponse response = client.execute(post);
|
||||
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
|
||||
throw new AddKeyException();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// nothing to do, better luck on the next keyserver
|
||||
} finally {
|
||||
client.getConnectionManager().shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
|
||||
*
|
||||
* 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 org.sufficientlysecure.keychain.util;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public class InputData {
|
||||
private PositionAwareInputStream mInputStream;
|
||||
private long mSize;
|
||||
|
||||
public InputData(InputStream inputStream, long size) {
|
||||
mInputStream = new PositionAwareInputStream(inputStream);
|
||||
mSize = size;
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
return mInputStream;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
public long getStreamPosition() {
|
||||
return mInputStream.position();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2012 ZXing authors
|
||||
*
|
||||
* 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 org.sufficientlysecure.keychain.util;
|
||||
|
||||
import com.google.zxing.integration.android.IntentIntegrator;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.support.v4.app.Fragment;
|
||||
|
||||
/**
|
||||
* IntentIntegrator for the V4 Android compatibility package.
|
||||
*
|
||||
* @author Lachezar Dobrev
|
||||
*/
|
||||
public final class IntentIntegratorSupportV4 extends IntentIntegrator {
|
||||
|
||||
private final Fragment mFragment;
|
||||
|
||||
/**
|
||||
* @param fragment Fragment to handle activity response.
|
||||
*/
|
||||
public IntentIntegratorSupportV4(Fragment fragment) {
|
||||
super(fragment.getActivity());
|
||||
this.mFragment = fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startActivityForResult(Intent intent, int code) {
|
||||
mFragment.startActivityForResult(intent, code);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
|
||||
*
|
||||
* 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 org.sufficientlysecure.keychain.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class IterableIterator<T> implements Iterable<T> {
|
||||
private Iterator<T> mIter;
|
||||
|
||||
public IterableIterator(Iterator<T> iter, boolean failsafe) {
|
||||
mIter = iter;
|
||||
if (failsafe && mIter == null) {
|
||||
// is there a better way?
|
||||
mIter = new ArrayList<T>().iterator();
|
||||
}
|
||||
}
|
||||
public IterableIterator(Iterator<T> iter) {
|
||||
this(iter, false);
|
||||
}
|
||||
|
||||
public Iterator<T> iterator() {
|
||||
return mIter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
* Copyright (C) 2011 Thialfihar <thi@thialfihar.org>
|
||||
* Copyright (C) 2011 Senecaso
|
||||
*
|
||||
* 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 org.sufficientlysecure.keychain.util;
|
||||
|
||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class KeyServer {
|
||||
public static class QueryException extends Exception {
|
||||
private static final long serialVersionUID = 2703768928624654512L;
|
||||
|
||||
public QueryException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static class TooManyResponses extends Exception {
|
||||
private static final long serialVersionUID = 2703768928624654513L;
|
||||
}
|
||||
|
||||
public static class InsufficientQuery extends Exception {
|
||||
private static final long serialVersionUID = 2703768928624654514L;
|
||||
}
|
||||
|
||||
public static class AddKeyException extends Exception {
|
||||
private static final long serialVersionUID = -507574859137295530L;
|
||||
}
|
||||
|
||||
abstract List<ImportKeysListEntry> search(String query) throws QueryException, TooManyResponses,
|
||||
InsufficientQuery;
|
||||
|
||||
abstract String get(String keyIdHex) throws QueryException;
|
||||
|
||||
abstract void add(String armoredKey) throws AddKeyException;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.util;
|
||||
|
||||
public interface KeychainServiceListener {
|
||||
boolean hasServiceStopped();
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.util;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
|
||||
/**
|
||||
* Wraps Android Logging to enable or disable debug output using Constants
|
||||
*/
|
||||
public final class Log {
|
||||
|
||||
public static void v(String tag, String msg) {
|
||||
if (Constants.DEBUG) {
|
||||
android.util.Log.v(tag, msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void v(String tag, String msg, Throwable tr) {
|
||||
if (Constants.DEBUG) {
|
||||
android.util.Log.v(tag, msg, tr);
|
||||
}
|
||||
}
|
||||
|
||||
public static void d(String tag, String msg) {
|
||||
if (Constants.DEBUG) {
|
||||
android.util.Log.d(tag, msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void d(String tag, String msg, Throwable tr) {
|
||||
if (Constants.DEBUG) {
|
||||
android.util.Log.d(tag, msg, tr);
|
||||
}
|
||||
}
|
||||
|
||||
public static void i(String tag, String msg) {
|
||||
if (Constants.DEBUG) {
|
||||
android.util.Log.i(tag, msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void i(String tag, String msg, Throwable tr) {
|
||||
if (Constants.DEBUG) {
|
||||
android.util.Log.i(tag, msg, tr);
|
||||
}
|
||||
}
|
||||
|
||||
public static void w(String tag, String msg) {
|
||||
android.util.Log.w(tag, msg);
|
||||
}
|
||||
|
||||
public static void w(String tag, String msg, Throwable tr) {
|
||||
android.util.Log.w(tag, msg, tr);
|
||||
}
|
||||
|
||||
public static void w(String tag, Throwable tr) {
|
||||
android.util.Log.w(tag, tr);
|
||||
}
|
||||
|
||||
public static void e(String tag, String msg) {
|
||||
android.util.Log.e(tag, msg);
|
||||
}
|
||||
|
||||
public static void e(String tag, String msg, Throwable tr) {
|
||||
android.util.Log.e(tag, msg, tr);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will Google be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, as long as the origin is not misrepresented.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.util;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Process;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.*;
|
||||
import java.security.*;
|
||||
|
||||
/**
|
||||
* Fixes for the output of the default PRNG having low entropy.
|
||||
* <p/>
|
||||
* The fixes need to be applied via {@link #apply()} before any use of Java Cryptography
|
||||
* Architecture primitives. A good place to invoke them is in the application's {@code onCreate}.
|
||||
* <p/>
|
||||
* copied from http://android-developers.blogspot.de/2013/08/some-securerandom-thoughts.html
|
||||
* <p/>
|
||||
* <p/>
|
||||
* More information on these Android bugs:
|
||||
* http://blog.k3170makan.com/2013/08/more-details-on-android-jca-prng-flaw.html
|
||||
* Paper: "Randomly failed! Weaknesses in Java Pseudo Random Number Generators (PRNGs)"
|
||||
* <p/>
|
||||
* <p/>
|
||||
* Sep 15, 2013:
|
||||
* On some devices /dev/urandom is non-writable!
|
||||
* No need to seed /dev/urandom. urandom should have enough seeds from the OS and kernel.
|
||||
* Only OpenSSL seeds are broken. See http://emboss.github.io/blog/2013/08/21/openssl-prng-is-not-really-fork-safe
|
||||
* <p/>
|
||||
* see also:
|
||||
* https://github.com/k9mail/k-9/commit/dda8f64276d4d29c43f86237cd77819c28f22f21
|
||||
* In addition to a couple of custom ROMs linking /dev/urandom to a non-writable
|
||||
* random version, now Samsung's SELinux policy also prevents apps from opening
|
||||
* /dev/urandom for writing. Since we shouldn't need to write to /dev/urandom anyway
|
||||
* we now simply don't.
|
||||
* <p/>
|
||||
* <p/>
|
||||
* Sep 17, 2013:
|
||||
* Updated from official blogpost:
|
||||
* Update: the original code sample below crashed on a small fraction of Android
|
||||
* devices due to /dev/urandom not being writable. We have now updated the code sample to handle this case gracefully.
|
||||
*/
|
||||
public final class PRNGFixes {
|
||||
|
||||
private static final int VERSION_CODE_JELLY_BEAN = 16;
|
||||
private static final int VERSION_CODE_JELLY_BEAN_MR2 = 18;
|
||||
private static final byte[] BUILD_FINGERPRINT_AND_DEVICE_SERIAL =
|
||||
getBuildFingerprintAndDeviceSerial();
|
||||
|
||||
/**
|
||||
* Hidden constructor to prevent instantiation.
|
||||
*/
|
||||
private PRNGFixes() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies all fixes.
|
||||
*
|
||||
* @throws SecurityException if a fix is needed but could not be applied.
|
||||
*/
|
||||
public static void apply() {
|
||||
applyOpenSSLFix();
|
||||
installLinuxPRNGSecureRandom();
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the fix for OpenSSL PRNG having low entropy. Does nothing if the
|
||||
* fix is not needed.
|
||||
*
|
||||
* @throws SecurityException if the fix is needed but could not be applied.
|
||||
*/
|
||||
private static void applyOpenSSLFix() throws SecurityException {
|
||||
if ((Build.VERSION.SDK_INT < VERSION_CODE_JELLY_BEAN)
|
||||
|| (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2)) {
|
||||
// No need to apply the fix
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Mix in the device- and invocation-specific seed.
|
||||
Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
|
||||
.getMethod("RAND_seed", byte[].class)
|
||||
.invoke(null, generateSeed());
|
||||
|
||||
// Mix output of Linux PRNG into OpenSSL's PRNG
|
||||
int bytesRead = (Integer) Class.forName(
|
||||
"org.apache.harmony.xnet.provider.jsse.NativeCrypto")
|
||||
.getMethod("RAND_load_file", String.class, long.class)
|
||||
.invoke(null, "/dev/urandom", 1024);
|
||||
if (bytesRead != 1024) {
|
||||
throw new IOException(
|
||||
"Unexpected number of bytes read from Linux PRNG: "
|
||||
+ bytesRead);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new SecurityException("Failed to seed OpenSSL PRNG", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs a Linux PRNG-backed {@code SecureRandom} implementation as the
|
||||
* default. Does nothing if the implementation is already the default or if
|
||||
* there is not need to install the implementation.
|
||||
*
|
||||
* @throws SecurityException if the fix is needed but could not be applied.
|
||||
*/
|
||||
private static void installLinuxPRNGSecureRandom()
|
||||
throws SecurityException {
|
||||
if (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2) {
|
||||
// No need to apply the fix
|
||||
return;
|
||||
}
|
||||
|
||||
// Install a Linux PRNG-based SecureRandom implementation as the
|
||||
// default, if not yet installed.
|
||||
Provider[] secureRandomProviders =
|
||||
Security.getProviders("SecureRandom.SHA1PRNG");
|
||||
if ((secureRandomProviders == null)
|
||||
|| (secureRandomProviders.length < 1)
|
||||
|| (!LinuxPRNGSecureRandomProvider.class.equals(
|
||||
secureRandomProviders[0].getClass()))) {
|
||||
Security.insertProviderAt(new LinuxPRNGSecureRandomProvider(), 1);
|
||||
}
|
||||
|
||||
// Assert that new SecureRandom() and
|
||||
// SecureRandom.getInstance("SHA1PRNG") return a SecureRandom backed
|
||||
// by the Linux PRNG-based SecureRandom implementation.
|
||||
SecureRandom rng1 = new SecureRandom();
|
||||
if (!LinuxPRNGSecureRandomProvider.class.equals(
|
||||
rng1.getProvider().getClass())) {
|
||||
throw new SecurityException(
|
||||
"new SecureRandom() backed by wrong Provider: "
|
||||
+ rng1.getProvider().getClass());
|
||||
}
|
||||
|
||||
SecureRandom rng2;
|
||||
try {
|
||||
rng2 = SecureRandom.getInstance("SHA1PRNG");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new SecurityException("SHA1PRNG not available", e);
|
||||
}
|
||||
if (!LinuxPRNGSecureRandomProvider.class.equals(
|
||||
rng2.getProvider().getClass())) {
|
||||
throw new SecurityException(
|
||||
"SecureRandom.getInstance(\"SHA1PRNG\") backed by wrong"
|
||||
+ " Provider: " + rng2.getProvider().getClass());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code Provider} of {@code SecureRandom} engines which pass through
|
||||
* all requests to the Linux PRNG.
|
||||
*/
|
||||
private static class LinuxPRNGSecureRandomProvider extends Provider {
|
||||
|
||||
public LinuxPRNGSecureRandomProvider() {
|
||||
super("LinuxPRNG",
|
||||
1.0,
|
||||
"A Linux-specific random number provider that uses"
|
||||
+ " /dev/urandom");
|
||||
// Although /dev/urandom is not a SHA-1 PRNG, some apps
|
||||
// explicitly request a SHA1PRNG SecureRandom and we thus need to
|
||||
// prevent them from getting the default implementation whose output
|
||||
// may have low entropy.
|
||||
put("SecureRandom.SHA1PRNG", LinuxPRNGSecureRandom.class.getName());
|
||||
put("SecureRandom.SHA1PRNG ImplementedIn", "Software");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link SecureRandomSpi} which passes all requests to the Linux PRNG
|
||||
* ({@code /dev/urandom}).
|
||||
*/
|
||||
public static class LinuxPRNGSecureRandom extends SecureRandomSpi {
|
||||
|
||||
/*
|
||||
* IMPLEMENTATION NOTE: Requests to generate bytes and to mix in a seed
|
||||
* are passed through to the Linux PRNG (/dev/urandom). Instances of
|
||||
* this class seed themselves by mixing in the current time, PID, UID,
|
||||
* build fingerprint, and hardware serial number (where available) into
|
||||
* Linux PRNG.
|
||||
*
|
||||
* Concurrency: Read requests to the underlying Linux PRNG are
|
||||
* serialized (on sLock) to ensure that multiple threads do not get
|
||||
* duplicated PRNG output.
|
||||
*/
|
||||
|
||||
private static final File URANDOM_FILE = new File("/dev/urandom");
|
||||
|
||||
private static final Object sLock = new Object();
|
||||
|
||||
/**
|
||||
* Input stream for reading from Linux PRNG or {@code null} if not yet
|
||||
* opened.
|
||||
*
|
||||
* @GuardedBy("sLock")
|
||||
*/
|
||||
private static DataInputStream sUrandomIn;
|
||||
|
||||
/**
|
||||
* Output stream for writing to Linux PRNG or {@code null} if not yet
|
||||
* opened.
|
||||
*
|
||||
* @GuardedBy("sLock")
|
||||
*/
|
||||
private static OutputStream sUrandomOut;
|
||||
|
||||
/**
|
||||
* Whether this engine instance has been seeded. This is needed because
|
||||
* each instance needs to seed itself if the client does not explicitly
|
||||
* seed it.
|
||||
*/
|
||||
private boolean mSeeded;
|
||||
|
||||
@Override
|
||||
protected void engineSetSeed(byte[] bytes) {
|
||||
try {
|
||||
OutputStream out;
|
||||
synchronized (sLock) {
|
||||
out = getUrandomOutputStream();
|
||||
}
|
||||
out.write(bytes);
|
||||
out.flush();
|
||||
} catch (IOException e) {
|
||||
// On a small fraction of devices /dev/urandom is not writable.
|
||||
// Log and ignore.
|
||||
Log.w(PRNGFixes.class.getSimpleName(),
|
||||
"Failed to mix seed into " + URANDOM_FILE);
|
||||
} finally {
|
||||
mSeeded = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineNextBytes(byte[] bytes) {
|
||||
if (!mSeeded) {
|
||||
// Mix in the device- and invocation-specific seed.
|
||||
engineSetSeed(generateSeed());
|
||||
}
|
||||
|
||||
try {
|
||||
DataInputStream in;
|
||||
synchronized (sLock) {
|
||||
in = getUrandomInputStream();
|
||||
}
|
||||
synchronized (in) {
|
||||
in.readFully(bytes);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException(
|
||||
"Failed to read from " + URANDOM_FILE, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] engineGenerateSeed(int size) {
|
||||
byte[] seed = new byte[size];
|
||||
engineNextBytes(seed);
|
||||
return seed;
|
||||
}
|
||||
|
||||
private DataInputStream getUrandomInputStream() {
|
||||
synchronized (sLock) {
|
||||
if (sUrandomIn == null) {
|
||||
// NOTE: Consider inserting a BufferedInputStream between
|
||||
// DataInputStream and FileInputStream if you need higher
|
||||
// PRNG output performance and can live with future PRNG
|
||||
// output being pulled into this process prematurely.
|
||||
try {
|
||||
sUrandomIn = new DataInputStream(
|
||||
new FileInputStream(URANDOM_FILE));
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Failed to open "
|
||||
+ URANDOM_FILE + " for reading", e);
|
||||
}
|
||||
}
|
||||
return sUrandomIn;
|
||||
}
|
||||
}
|
||||
|
||||
private OutputStream getUrandomOutputStream() throws IOException {
|
||||
synchronized (sLock) {
|
||||
if (sUrandomOut == null) {
|
||||
sUrandomOut = new FileOutputStream(URANDOM_FILE);
|
||||
}
|
||||
return sUrandomOut;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a device- and invocation-specific seed to be mixed into the
|
||||
* Linux PRNG.
|
||||
*/
|
||||
private static byte[] generateSeed() {
|
||||
try {
|
||||
ByteArrayOutputStream seedBuffer = new ByteArrayOutputStream();
|
||||
DataOutputStream seedBufferOut =
|
||||
new DataOutputStream(seedBuffer);
|
||||
seedBufferOut.writeLong(System.currentTimeMillis());
|
||||
seedBufferOut.writeLong(System.nanoTime());
|
||||
seedBufferOut.writeInt(Process.myPid());
|
||||
seedBufferOut.writeInt(Process.myUid());
|
||||
seedBufferOut.write(BUILD_FINGERPRINT_AND_DEVICE_SERIAL);
|
||||
seedBufferOut.close();
|
||||
return seedBuffer.toByteArray();
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Failed to generate seed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hardware serial number of this device.
|
||||
*
|
||||
* @return serial number or {@code null} if not available.
|
||||
*/
|
||||
private static String getDeviceSerialNumber() {
|
||||
// We're using the Reflection API because Build.SERIAL is only available
|
||||
// since API Level 9 (Gingerbread, Android 2.3).
|
||||
try {
|
||||
return (String) Build.class.getField("SERIAL").get(null);
|
||||
} catch (Exception ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] getBuildFingerprintAndDeviceSerial() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
String fingerprint = Build.FINGERPRINT;
|
||||
if (fingerprint != null) {
|
||||
result.append(fingerprint);
|
||||
}
|
||||
String serial = getDeviceSerialNumber();
|
||||
if (serial != null) {
|
||||
result.append(serial);
|
||||
}
|
||||
try {
|
||||
return result.toString().getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException("UTF-8 encoding not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.util;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.RejectedExecutionHandler;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Example from
|
||||
* http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ThreadPoolExecutor.html
|
||||
*/
|
||||
public class PausableThreadPoolExecutor extends ThreadPoolExecutor {
|
||||
|
||||
public PausableThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
|
||||
TimeUnit unit, BlockingQueue<Runnable> workQueue,
|
||||
RejectedExecutionHandler handler) {
|
||||
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
|
||||
}
|
||||
|
||||
public PausableThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
|
||||
TimeUnit unit, BlockingQueue<Runnable> workQueue,
|
||||
ThreadFactory threadFactory,
|
||||
RejectedExecutionHandler handler) {
|
||||
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
|
||||
}
|
||||
|
||||
public PausableThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
|
||||
TimeUnit unit, BlockingQueue<Runnable> workQueue,
|
||||
ThreadFactory threadFactory) {
|
||||
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
|
||||
}
|
||||
|
||||
public PausableThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
|
||||
TimeUnit unit, BlockingQueue<Runnable> workQueue) {
|
||||
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
|
||||
}
|
||||
|
||||
private boolean mIsPaused;
|
||||
private ReentrantLock mPauseLock = new ReentrantLock();
|
||||
private Condition mUnPaused = mPauseLock.newCondition();
|
||||
|
||||
protected void beforeExecute(Thread t, Runnable r) {
|
||||
super.beforeExecute(t, r);
|
||||
mPauseLock.lock();
|
||||
try {
|
||||
while (mIsPaused) {
|
||||
mUnPaused.await();
|
||||
}
|
||||
} catch (InterruptedException ie) {
|
||||
t.interrupt();
|
||||
} finally {
|
||||
mPauseLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
mPauseLock.lock();
|
||||
try {
|
||||
mIsPaused = true;
|
||||
} finally {
|
||||
mPauseLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void resume() {
|
||||
mPauseLock.lock();
|
||||
try {
|
||||
mIsPaused = false;
|
||||
mUnPaused.signalAll();
|
||||
} finally {
|
||||
mPauseLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
|
||||
*
|
||||
* 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 org.sufficientlysecure.keychain.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class PositionAwareInputStream extends InputStream {
|
||||
private InputStream mStream;
|
||||
private long mPosition;
|
||||
|
||||
public PositionAwareInputStream(InputStream in) {
|
||||
mStream = in;
|
||||
mPosition = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
int ch = mStream.read();
|
||||
++mPosition;
|
||||
return ch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return mStream.available();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
mStream.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean markSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b) throws IOException {
|
||||
int result = mStream.read(b);
|
||||
mPosition += result;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int offset, int length) throws IOException {
|
||||
int result = mStream.read(b, offset, length);
|
||||
mPosition += result;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void reset() throws IOException {
|
||||
mStream.reset();
|
||||
mPosition = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long n) throws IOException {
|
||||
long result = mStream.skip(n);
|
||||
mPosition += result;
|
||||
return result;
|
||||
}
|
||||
|
||||
public long position() {
|
||||
return mPosition;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
|
||||
*
|
||||
* 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 org.sufficientlysecure.keychain.util;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Primes for ElGamal
|
||||
*/
|
||||
public final class Primes {
|
||||
// taken from http://www.ietf.org/rfc/rfc3526.txt
|
||||
public static final String P1536 =
|
||||
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
|
||||
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
|
||||
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
|
||||
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
|
||||
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
|
||||
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
|
||||
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
|
||||
"670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF";
|
||||
|
||||
public static final String P2048 =
|
||||
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
|
||||
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
|
||||
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
|
||||
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
|
||||
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
|
||||
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
|
||||
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
|
||||
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
|
||||
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
|
||||
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
|
||||
"15728E5A 8AACAA68 FFFFFFFF FFFFFFFF";
|
||||
|
||||
public static final String P3072 =
|
||||
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
|
||||
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
|
||||
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
|
||||
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
|
||||
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
|
||||
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
|
||||
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
|
||||
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
|
||||
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
|
||||
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
|
||||
"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
|
||||
"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
|
||||
"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
|
||||
"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
|
||||
"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
|
||||
"43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF";
|
||||
|
||||
public static final String P4096 =
|
||||
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
|
||||
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
|
||||
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
|
||||
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
|
||||
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
|
||||
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
|
||||
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
|
||||
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
|
||||
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
|
||||
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
|
||||
"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
|
||||
"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
|
||||
"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
|
||||
"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
|
||||
"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
|
||||
"43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
|
||||
"88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
|
||||
"2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
|
||||
"287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
|
||||
"1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
|
||||
"93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199" +
|
||||
"FFFFFFFF FFFFFFFF";
|
||||
|
||||
public static final String P6144 =
|
||||
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
|
||||
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
|
||||
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
|
||||
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
|
||||
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
|
||||
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
|
||||
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
|
||||
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
|
||||
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
|
||||
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
|
||||
"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
|
||||
"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
|
||||
"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
|
||||
"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
|
||||
"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
|
||||
"43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
|
||||
"88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
|
||||
"2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
|
||||
"287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
|
||||
"1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
|
||||
"93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" +
|
||||
"36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" +
|
||||
"F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" +
|
||||
"179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" +
|
||||
"DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" +
|
||||
"5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" +
|
||||
"D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" +
|
||||
"23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" +
|
||||
"CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" +
|
||||
"06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" +
|
||||
"DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" +
|
||||
"12BF2D5B 0B7474D6 E694F91E 6DCC4024 FFFFFFFF FFFFFFFF";
|
||||
|
||||
public static final String P8192 =
|
||||
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" +
|
||||
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" +
|
||||
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" +
|
||||
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" +
|
||||
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" +
|
||||
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" +
|
||||
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" +
|
||||
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" +
|
||||
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" +
|
||||
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" +
|
||||
"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" +
|
||||
"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" +
|
||||
"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" +
|
||||
"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" +
|
||||
"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" +
|
||||
"43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" +
|
||||
"88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" +
|
||||
"2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" +
|
||||
"287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" +
|
||||
"1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" +
|
||||
"93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" +
|
||||
"36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" +
|
||||
"F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" +
|
||||
"179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" +
|
||||
"DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" +
|
||||
"5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" +
|
||||
"D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" +
|
||||
"23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" +
|
||||
"CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" +
|
||||
"06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" +
|
||||
"DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" +
|
||||
"12BF2D5B 0B7474D6 E694F91E 6DBE1159 74A3926F 12FEE5E4" +
|
||||
"38777CB6 A932DF8C D8BEC4D0 73B931BA 3BC832B6 8D9DD300" +
|
||||
"741FA7BF 8AFC47ED 2576F693 6BA42466 3AAB639C 5AE4F568" +
|
||||
"3423B474 2BF1C978 238F16CB E39D652D E3FDB8BE FC848AD9" +
|
||||
"22222E04 A4037C07 13EB57A8 1A23F0C7 3473FC64 6CEA306B" +
|
||||
"4BCBC886 2F8385DD FA9D4B7F A2C087E8 79683303 ED5BDD3A" +
|
||||
"062B3CF5 B3A278A6 6D2A13F8 3F44F82D DF310EE0 74AB6A36" +
|
||||
"4597E899 A0255DC1 64F31CC5 0846851D F9AB4819 5DED7EA1" +
|
||||
"B1D510BD 7EE74D73 FAF36BC3 1ECFA268 359046F4 EB879F92" +
|
||||
"4009438B 481C6CD7 889A002E D5EE382B C9190DA6 FC026E47" +
|
||||
"9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71" +
|
||||
"60C980DD 98EDD3DF FFFFFFFF FFFFFFFF";
|
||||
|
||||
public static BigInteger getBestPrime(int keySize) {
|
||||
String primeString;
|
||||
if (keySize >= (8192 + 6144) / 2) {
|
||||
primeString = P8192;
|
||||
} else if (keySize >= (6144 + 4096) / 2) {
|
||||
primeString = P6144;
|
||||
} else if (keySize >= (4096 + 3072) / 2) {
|
||||
primeString = P4096;
|
||||
} else if (keySize >= (3072 + 2048) / 2) {
|
||||
primeString = P3072;
|
||||
} else if (keySize >= (2048 + 1536) / 2) {
|
||||
primeString = P2048;
|
||||
} else {
|
||||
primeString = P1536;
|
||||
}
|
||||
|
||||
return new BigInteger(primeString.replaceAll(" ", ""), 16);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
|
||||
*
|
||||
* 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 org.sufficientlysecure.keychain.util;
|
||||
|
||||
public interface ProgressDialogUpdater {
|
||||
void setProgress(String message, int current, int total);
|
||||
|
||||
void setProgress(int resourceId, int current, int total);
|
||||
|
||||
void setProgress(int current, int total);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.util;
|
||||
|
||||
/** This is a simple class that wraps a ProgressDialogUpdater, scaling the progress
|
||||
* values into a specified range.
|
||||
*/
|
||||
public class ProgressScaler implements ProgressDialogUpdater {
|
||||
|
||||
final ProgressDialogUpdater mWrapped;
|
||||
final int mFrom, mTo, mMax;
|
||||
|
||||
public ProgressScaler(ProgressDialogUpdater wrapped, int from, int to, int max) {
|
||||
this.mWrapped = wrapped;
|
||||
this.mFrom = from;
|
||||
this.mTo = to;
|
||||
this.mMax = max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set progressDialogUpdater of ProgressDialog by sending message to handler on UI thread
|
||||
*/
|
||||
public void setProgress(String message, int progress, int max) {
|
||||
mWrapped.setProgress(message, mFrom + progress * (mTo - mFrom) / max, mMax);
|
||||
}
|
||||
|
||||
public void setProgress(int resourceId, int progress, int max) {
|
||||
mWrapped.setProgress(resourceId, progress, mMax);
|
||||
}
|
||||
|
||||
public void setProgress(int progress, int max) {
|
||||
mWrapped.setProgress(progress, max);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
* Copyright (C) 2011 Andreas Schildbach
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.util;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.EncodeHintType;
|
||||
import com.google.zxing.WriterException;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.qrcode.QRCodeWriter;
|
||||
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
public class QrCodeUtils {
|
||||
public static final QRCodeWriter QR_CODE_WRITER = new QRCodeWriter();
|
||||
|
||||
/**
|
||||
* Generate Bitmap with QR Code based on input.
|
||||
*
|
||||
* @param input
|
||||
* @param size
|
||||
* @return QR Code as Bitmap
|
||||
*/
|
||||
public static Bitmap getQRCodeBitmap(final String input, final int size) {
|
||||
try {
|
||||
final Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
|
||||
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
|
||||
final BitMatrix result = QR_CODE_WRITER.encode(input, BarcodeFormat.QR_CODE, size,
|
||||
size, hints);
|
||||
|
||||
final int width = result.getWidth();
|
||||
final int height = result.getHeight();
|
||||
final int[] pixels = new int[width * height];
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
final int offset = y * width;
|
||||
for (int x = 0; x < width; x++) {
|
||||
pixels[offset + x] = result.get(x, y) ? Color.BLACK : Color.TRANSPARENT;
|
||||
}
|
||||
}
|
||||
|
||||
final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
|
||||
return bitmap;
|
||||
} catch (final WriterException e) {
|
||||
Log.e(Constants.TAG, "QrCodeUtils", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user