Merge branch 'master' of github.com:open-keychain/open-keychain

This commit is contained in:
Dominik Schürmann
2016-04-18 07:31:38 +02:00
12 changed files with 48 additions and 29 deletions

View File

@@ -47,7 +47,7 @@ import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
import org.sufficientlysecure.keychain.service.UploadKeyringParcel; import org.sufficientlysecure.keychain.service.UploadKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.NfcSignOperationsBuilder; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.SecurityTokenSignOperationsBuilder;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.Passphrase; import org.sufficientlysecure.keychain.util.Passphrase;
@@ -144,7 +144,7 @@ public class CertifyOperation extends BaseOperation<CertifyActionsParcel> {
int certifyOk = 0, certifyError = 0, uploadOk = 0, uploadError = 0; int certifyOk = 0, certifyError = 0, uploadOk = 0, uploadError = 0;
NfcSignOperationsBuilder allRequiredInput = new NfcSignOperationsBuilder( SecurityTokenSignOperationsBuilder allRequiredInput = new SecurityTokenSignOperationsBuilder(
cryptoInput.getSignatureTime(), masterKeyId, masterKeyId); cryptoInput.getSignatureTime(), masterKeyId, masterKeyId);
// Work through all requested certifications // Work through all requested certifications

View File

@@ -43,7 +43,7 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.NfcSignOperationsBuilder; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.SecurityTokenSignOperationsBuilder;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.RequiredInputType; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.RequiredInputType;
import org.sufficientlysecure.keychain.util.FileHelper; import org.sufficientlysecure.keychain.util.FileHelper;
import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.InputData;
@@ -80,7 +80,7 @@ public class SignEncryptOperation extends BaseOperation<SignEncryptParcel> {
int total = inputBytes != null ? 1 : inputUris.size(), count = 0; int total = inputBytes != null ? 1 : inputUris.size(), count = 0;
ArrayList<PgpSignEncryptResult> results = new ArrayList<>(); ArrayList<PgpSignEncryptResult> results = new ArrayList<>();
NfcSignOperationsBuilder pendingInputBuilder = null; SecurityTokenSignOperationsBuilder pendingInputBuilder = null;
// if signing subkey has not explicitly been set, get first usable subkey capable of signing // if signing subkey has not explicitly been set, get first usable subkey capable of signing
if (input.getSignatureMasterKeyId() != Constants.key.none if (input.getSignatureMasterKeyId() != Constants.key.none
@@ -161,7 +161,7 @@ public class SignEncryptOperation extends BaseOperation<SignEncryptParcel> {
return new SignEncryptResult(log, requiredInput, results, cryptoInput); return new SignEncryptResult(log, requiredInput, results, cryptoInput);
} }
if (pendingInputBuilder == null) { if (pendingInputBuilder == null) {
pendingInputBuilder = new NfcSignOperationsBuilder(requiredInput.mSignatureTime, pendingInputBuilder = new SecurityTokenSignOperationsBuilder(requiredInput.mSignatureTime,
input.getSignatureMasterKeyId(), input.getSignatureSubKeyId()); input.getSignatureMasterKeyId(), input.getSignatureSubKeyId());
} }
pendingInputBuilder.addAll(requiredInput); pendingInputBuilder.addAll(requiredInput);

View File

@@ -37,7 +37,7 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult.LogTyp
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction; import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.NfcSignOperationsBuilder; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.SecurityTokenSignOperationsBuilder;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
@@ -76,7 +76,7 @@ public class PgpCertifyOperation {
// get the master subkey (which we certify for) // get the master subkey (which we certify for)
PGPPublicKey publicKey = publicRing.getPublicKey().getPublicKey(); PGPPublicKey publicKey = publicRing.getPublicKey().getPublicKey();
NfcSignOperationsBuilder requiredInput = new NfcSignOperationsBuilder(creationTimestamp, SecurityTokenSignOperationsBuilder requiredInput = new SecurityTokenSignOperationsBuilder(creationTimestamp,
publicKey.getKeyID(), publicKey.getKeyID()); publicKey.getKeyID(), publicKey.getKeyID());
try { try {

View File

@@ -769,7 +769,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
&& !decryptorFactory.hasCachedSessionData(encryptedDataAsymmetric)) { && !decryptorFactory.hasCachedSessionData(encryptedDataAsymmetric)) {
log.add(LogType.MSG_DC_PENDING_NFC, indent + 1); log.add(LogType.MSG_DC_PENDING_NFC, indent + 1);
return result.with(new DecryptVerifyResult(log, RequiredInputParcel.createNfcDecryptOperation( return result.with(new DecryptVerifyResult(log, RequiredInputParcel.createSecurityTokenDecryptOperation(
decryptionKey.getRing().getMasterKeyId(), decryptionKey.getRing().getMasterKeyId(),
decryptionKey.getKeyId(), encryptedDataAsymmetric.getSessionKey()[0] decryptionKey.getKeyId(), encryptedDataAsymmetric.getSessionKey()[0]
), cryptoInput)); ), cryptoInput));

View File

@@ -78,8 +78,8 @@ import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Curve;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.NfcKeyToCardOperationsBuilder; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.SecurityTokenKeyToCardOperationsBuilder;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.NfcSignOperationsBuilder; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.SecurityTokenSignOperationsBuilder;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
@@ -496,10 +496,10 @@ public class PgpKeyOperation {
OperationLog log, OperationLog log,
int indent) { int indent) {
NfcSignOperationsBuilder nfcSignOps = new NfcSignOperationsBuilder( SecurityTokenSignOperationsBuilder nfcSignOps = new SecurityTokenSignOperationsBuilder(
cryptoInput.getSignatureTime(), masterSecretKey.getKeyID(), cryptoInput.getSignatureTime(), masterSecretKey.getKeyID(),
masterSecretKey.getKeyID()); masterSecretKey.getKeyID());
NfcKeyToCardOperationsBuilder nfcKeyToCardOps = new NfcKeyToCardOperationsBuilder( SecurityTokenKeyToCardOperationsBuilder nfcKeyToCardOps = new SecurityTokenKeyToCardOperationsBuilder(
masterSecretKey.getKeyID()); masterSecretKey.getKeyID());
progress(R.string.progress_modify, 0); progress(R.string.progress_modify, 0);
@@ -1277,7 +1277,7 @@ public class PgpKeyOperation {
PGPPublicKey masterPublicKey, PGPPublicKey masterPublicKey,
int flags, long expiry, int flags, long expiry,
CryptoInputParcel cryptoInput, CryptoInputParcel cryptoInput,
NfcSignOperationsBuilder nfcSignOps, SecurityTokenSignOperationsBuilder nfcSignOps,
int indent, OperationLog log) int indent, OperationLog log)
throws PGPException, IOException, SignatureException { throws PGPException, IOException, SignatureException {

View File

@@ -520,7 +520,7 @@ public class PgpSignEncryptOperation extends BaseOperation {
} catch (NfcSyncPGPContentSignerBuilder.NfcInteractionNeeded e) { } catch (NfcSyncPGPContentSignerBuilder.NfcInteractionNeeded e) {
// this secret key diverts to a OpenPGP card, throw exception with hash that will be signed // this secret key diverts to a OpenPGP card, throw exception with hash that will be signed
log.add(LogType.MSG_PSE_PENDING_NFC, indent); log.add(LogType.MSG_PSE_PENDING_NFC, indent);
return new PgpSignEncryptResult(log, RequiredInputParcel.createNfcSignOperation( return new PgpSignEncryptResult(log, RequiredInputParcel.createSecurityTokenSignOperation(
signingKey.getRing().getMasterKeyId(), signingKey.getKeyId(), signingKey.getRing().getMasterKeyId(), signingKey.getKeyId(),
e.hashToSign, e.hashAlgo, cryptoInput.getSignatureTime()), cryptoInput); e.hashToSign, e.hashAlgo, cryptoInput.getSignatureTime()), cryptoInput);
} }

View File

@@ -53,7 +53,7 @@ public class ApiPendingIntentFactory {
case SECURITY_TOKEN_MOVE_KEY_TO_CARD: case SECURITY_TOKEN_MOVE_KEY_TO_CARD:
case SECURITY_TOKEN_DECRYPT: case SECURITY_TOKEN_DECRYPT:
case SECURITY_TOKEN_SIGN: { case SECURITY_TOKEN_SIGN: {
return createNfcOperationPendingIntent(data, requiredInput, cryptoInput); return createSecurityTokenOperationPendingIntent(data, requiredInput, cryptoInput);
} }
case PASSPHRASE: { case PASSPHRASE: {
@@ -65,7 +65,7 @@ public class ApiPendingIntentFactory {
} }
} }
private PendingIntent createNfcOperationPendingIntent(Intent data, RequiredInputParcel requiredInput, CryptoInputParcel cryptoInput) { private PendingIntent createSecurityTokenOperationPendingIntent(Intent data, RequiredInputParcel requiredInput, CryptoInputParcel cryptoInput) {
Intent intent = new Intent(mContext, RemoteSecurityTokenOperationActivity.class); Intent intent = new Intent(mContext, RemoteSecurityTokenOperationActivity.class);
// pass params through to activity that it can be returned again later to repeat pgp operation // pass params through to activity that it can be returned again later to repeat pgp operation
intent.putExtra(RemoteSecurityTokenOperationActivity.EXTRA_REQUIRED_INPUT, requiredInput); intent.putExtra(RemoteSecurityTokenOperationActivity.EXTRA_REQUIRED_INPUT, requiredInput);

View File

@@ -22,6 +22,8 @@
package org.sufficientlysecure.keychain.securitytoken; package org.sufficientlysecure.keychain.securitytoken;
import android.support.annotation.NonNull;
import org.bouncycastle.bcpg.HashAlgorithmTags; import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.encoders.Hex;
@@ -131,13 +133,13 @@ public class SecurityTokenHelper {
private boolean isSlotEmpty(KeyType keyType) throws IOException { private boolean isSlotEmpty(KeyType keyType) throws IOException {
// Note: special case: This should not happen, but happens with // Note: special case: This should not happen, but happens with
// https://github.com/FluffyKaon/OpenPGP-Card, thus for now assume true // https://github.com/FluffyKaon/OpenPGP-Card, thus for now assume true
if (getMasterKeyFingerprint(keyType.getIdx()) == null) return true; if (getKeyFingerprint(keyType) == null) return true;
return keyMatchesFingerPrint(keyType, BLANK_FINGERPRINT); return keyMatchesFingerPrint(keyType, BLANK_FINGERPRINT);
} }
public boolean keyMatchesFingerPrint(KeyType keyType, byte[] fingerprint) throws IOException { public boolean keyMatchesFingerPrint(KeyType keyType, byte[] fingerprint) throws IOException {
return java.util.Arrays.equals(getMasterKeyFingerprint(keyType.getIdx()), fingerprint); return java.util.Arrays.equals(getKeyFingerprint(keyType), fingerprint);
} }
/** /**
@@ -723,10 +725,10 @@ public class SecurityTokenHelper {
* Return the fingerprint from application specific data stored on tag, or * Return the fingerprint from application specific data stored on tag, or
* null if it doesn't exist. * null if it doesn't exist.
* *
* @param idx Index of the key to return the fingerprint from. * @param keyType key type
* @return The fingerprint of the requested key, or null if not found. * @return The fingerprint of the requested key, or null if not found.
*/ */
public byte[] getMasterKeyFingerprint(int idx) throws IOException { public byte[] getKeyFingerprint(@NonNull KeyType keyType) throws IOException {
byte[] data = getFingerprints(); byte[] data = getFingerprints();
if (data == null) { if (data == null) {
return null; return null;
@@ -735,7 +737,7 @@ public class SecurityTokenHelper {
// return the master key fingerprint // return the master key fingerprint
ByteBuffer fpbuf = ByteBuffer.wrap(data); ByteBuffer fpbuf = ByteBuffer.wrap(data);
byte[] fp = new byte[20]; byte[] fp = new byte[20];
fpbuf.position(idx * 20); fpbuf.position(keyType.getIdx() * 20);
fpbuf.get(fp, 0, 20); fpbuf.get(fp, 0, 20);
return fp; return fp;

View File

@@ -89,7 +89,7 @@ public class RequiredInputParcel implements Parcelable {
return new RequiredInputParcel(RequiredInputType.ENABLE_ORBOT, null, null, null, 0L, 0L); return new RequiredInputParcel(RequiredInputType.ENABLE_ORBOT, null, null, null, 0L, 0L);
} }
public static RequiredInputParcel createNfcSignOperation( public static RequiredInputParcel createSecurityTokenSignOperation(
long masterKeyId, long subKeyId, long masterKeyId, long subKeyId,
byte[] inputHash, int signAlgo, Date signatureTime) { byte[] inputHash, int signAlgo, Date signatureTime) {
return new RequiredInputParcel(RequiredInputType.SECURITY_TOKEN_SIGN, return new RequiredInputParcel(RequiredInputType.SECURITY_TOKEN_SIGN,
@@ -97,13 +97,13 @@ public class RequiredInputParcel implements Parcelable {
signatureTime, masterKeyId, subKeyId); signatureTime, masterKeyId, subKeyId);
} }
public static RequiredInputParcel createNfcDecryptOperation( public static RequiredInputParcel createSecurityTokenDecryptOperation(
long masterKeyId, long subKeyId, byte[] encryptedSessionKey) { long masterKeyId, long subKeyId, byte[] encryptedSessionKey) {
return new RequiredInputParcel(RequiredInputType.SECURITY_TOKEN_DECRYPT, return new RequiredInputParcel(RequiredInputType.SECURITY_TOKEN_DECRYPT,
new byte[][] { encryptedSessionKey }, null, null, masterKeyId, subKeyId); new byte[][] { encryptedSessionKey }, null, null, masterKeyId, subKeyId);
} }
public static RequiredInputParcel createNfcReset() { public static RequiredInputParcel createSecurityTokenReset() {
return new RequiredInputParcel(RequiredInputType.SECURITY_TOKEN_RESET_CARD, return new RequiredInputParcel(RequiredInputType.SECURITY_TOKEN_RESET_CARD,
null, null, null, null, null); null, null, null, null, null);
} }
@@ -188,14 +188,14 @@ public class RequiredInputParcel implements Parcelable {
} }
}; };
public static class NfcSignOperationsBuilder { public static class SecurityTokenSignOperationsBuilder {
Date mSignatureTime; Date mSignatureTime;
ArrayList<Integer> mSignAlgos = new ArrayList<>(); ArrayList<Integer> mSignAlgos = new ArrayList<>();
ArrayList<byte[]> mInputHashes = new ArrayList<>(); ArrayList<byte[]> mInputHashes = new ArrayList<>();
long mMasterKeyId; long mMasterKeyId;
long mSubKeyId; long mSubKeyId;
public NfcSignOperationsBuilder(Date signatureTime, long masterKeyId, long subKeyId) { public SecurityTokenSignOperationsBuilder(Date signatureTime, long masterKeyId, long subKeyId) {
mSignatureTime = signatureTime; mSignatureTime = signatureTime;
mMasterKeyId = masterKeyId; mMasterKeyId = masterKeyId;
mSubKeyId = subKeyId; mSubKeyId = subKeyId;
@@ -238,13 +238,13 @@ public class RequiredInputParcel implements Parcelable {
} }
public static class NfcKeyToCardOperationsBuilder { public static class SecurityTokenKeyToCardOperationsBuilder {
ArrayList<byte[]> mSubkeysToExport = new ArrayList<>(); ArrayList<byte[]> mSubkeysToExport = new ArrayList<>();
Long mMasterKeyId; Long mMasterKeyId;
byte[] mPin; byte[] mPin;
byte[] mAdminPin; byte[] mAdminPin;
public NfcKeyToCardOperationsBuilder(Long masterKeyId) { public SecurityTokenKeyToCardOperationsBuilder(Long masterKeyId) {
mMasterKeyId = masterKeyId; mMasterKeyId = masterKeyId;
} }

View File

@@ -230,7 +230,7 @@ public class CreateSecurityTokenImportResetFragment
public void resetCard() { public void resetCard() {
Intent intent = new Intent(getActivity(), SecurityTokenOperationActivity.class); Intent intent = new Intent(getActivity(), SecurityTokenOperationActivity.class);
RequiredInputParcel resetP = RequiredInputParcel.createNfcReset(); RequiredInputParcel resetP = RequiredInputParcel.createSecurityTokenReset();
intent.putExtra(SecurityTokenOperationActivity.EXTRA_REQUIRED_INPUT, resetP); intent.putExtra(SecurityTokenOperationActivity.EXTRA_REQUIRED_INPUT, resetP);
intent.putExtra(SecurityTokenOperationActivity.EXTRA_CRYPTO_INPUT, new CryptoInputParcel()); intent.putExtra(SecurityTokenOperationActivity.EXTRA_CRYPTO_INPUT, new CryptoInputParcel());
startActivityForResult(intent, REQUEST_CODE_RESET); startActivityForResult(intent, REQUEST_CODE_RESET);

View File

@@ -36,10 +36,12 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.securitytoken.KeyType;
import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel; import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.base.BaseSecurityTokenNfcActivity; import org.sufficientlysecure.keychain.ui.base.BaseSecurityTokenNfcActivity;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.ui.util.ThemeChanger; import org.sufficientlysecure.keychain.ui.util.ThemeChanger;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.OrientationUtils; import org.sufficientlysecure.keychain.util.OrientationUtils;
@@ -183,6 +185,13 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenNfcActivity
switch (mRequiredInput.mType) { switch (mRequiredInput.mType) {
case SECURITY_TOKEN_DECRYPT: { case SECURITY_TOKEN_DECRYPT: {
long tokenKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(
mSecurityTokenHelper.getKeyFingerprint(KeyType.ENCRYPT));
if (tokenKeyId != mRequiredInput.getSubKeyId()) {
throw new IOException(getString(R.string.error_wrong_security_token));
}
for (int i = 0; i < mRequiredInput.mInputData.length; i++) { for (int i = 0; i < mRequiredInput.mInputData.length; i++) {
byte[] encryptedSessionKey = mRequiredInput.mInputData[i]; byte[] encryptedSessionKey = mRequiredInput.mInputData[i];
byte[] decryptedSessionKey = mSecurityTokenHelper.decryptSessionKey(encryptedSessionKey); byte[] decryptedSessionKey = mSecurityTokenHelper.decryptSessionKey(encryptedSessionKey);
@@ -191,6 +200,13 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenNfcActivity
break; break;
} }
case SECURITY_TOKEN_SIGN: { case SECURITY_TOKEN_SIGN: {
long tokenKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(
mSecurityTokenHelper.getKeyFingerprint(KeyType.SIGN));
if (tokenKeyId != mRequiredInput.getSubKeyId()) {
throw new IOException(getString(R.string.error_wrong_security_token));
}
mInputParcel.addSignatureTime(mRequiredInput.mSignatureTime); mInputParcel.addSignatureTime(mRequiredInput.mSignatureTime);
for (int i = 0; i < mRequiredInput.mInputData.length; i++) { for (int i = 0; i < mRequiredInput.mInputData.length; i++) {

View File

@@ -380,6 +380,7 @@
<string name="error_integrity_check_failed">"integrity check failed! Data has been modified!"</string> <string name="error_integrity_check_failed">"integrity check failed! Data has been modified!"</string>
<string name="error_wrong_passphrase">"wrong password"</string> <string name="error_wrong_passphrase">"wrong password"</string>
<string name="error_could_not_extract_private_key">"could not extract private key"</string> <string name="error_could_not_extract_private_key">"could not extract private key"</string>
<string name="error_wrong_security_token">"this security token doesn't contain required key"</string>
<!-- errors without preceeding Error: --> <!-- errors without preceeding Error: -->
<string name="error_jelly_bean_needed">"You need Android 4.1 to use Android's NFC Beam feature!"</string> <string name="error_jelly_bean_needed">"You need Android 4.1 to use Android's NFC Beam feature!"</string>