commit
f4cada5fa1
|
@ -1310,7 +1310,6 @@ Java_com_m2049r_xmrwallet_model_PendingTransaction_getFirstTxIdJ(JNIEnv *env, jo
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_com_m2049r_xmrwallet_model_PendingTransaction_getTxCount(JNIEnv *env, jobject instance) {
|
||||
Bitmonero::PendingTransaction *tx = getHandle<Bitmonero::PendingTransaction>(env, instance);
|
||||
|
@ -1396,6 +1395,11 @@ Java_com_m2049r_xmrwallet_model_WalletManager_setLogLevel(JNIEnv *env, jclass cl
|
|||
Bitmonero::WalletManagerFactory::setLogLevel(level);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_m2049r_xmrwallet_model_WalletManager_moneroVersion(JNIEnv *env, jclass clazz) {
|
||||
return env->NewStringUTF(MONERO_VERSION);
|
||||
}
|
||||
|
||||
//
|
||||
// Ledger Stuff
|
||||
//
|
||||
|
|
|
@ -54,6 +54,8 @@ extern "C"
|
|||
{
|
||||
#endif
|
||||
|
||||
extern const char* const MONERO_VERSION; // the actual monero core version
|
||||
|
||||
// from monero-core crypto/hash-ops.h - avoid #including monero code here
|
||||
enum {
|
||||
HASH_SIZE = 32,
|
||||
|
|
|
@ -46,8 +46,12 @@ public class BTChipTransportAndroidHID implements BTChipTransport {
|
|||
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
|
||||
for (UsbDevice device : deviceList.values()) {
|
||||
Timber.d("%04X:%04X %s, %s", device.getVendorId(), device.getProductId(), device.getManufacturerName(), device.getProductName());
|
||||
if ((device.getVendorId() == VID) && (device.getProductId() == PID_HID)) {
|
||||
return device;
|
||||
if (device.getVendorId() == VID) {
|
||||
final int deviceProductId = device.getProductId();
|
||||
for (int pid : PID_HIDS) {
|
||||
if (deviceProductId == pid)
|
||||
return device;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -74,7 +78,7 @@ public class BTChipTransportAndroidHID implements BTChipTransport {
|
|||
}
|
||||
|
||||
private static final int VID = 0x2C97;
|
||||
private static final int PID_HID = 0x0001;
|
||||
private static final int[] PID_HIDS = {0x0001, 0x0004};
|
||||
|
||||
private UsbDeviceConnection connection;
|
||||
private UsbInterface dongleInterface;
|
||||
|
|
|
@ -1359,17 +1359,30 @@ public class LoginActivity extends BaseActivity
|
|||
if (Ledger.ENABLED)
|
||||
try {
|
||||
Ledger.connect(usbManager, usbDevice);
|
||||
registerDetachReceiver();
|
||||
onLedgerAction();
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(LoginActivity.this,
|
||||
getString(R.string.toast_ledger_attached, usbDevice.getProductName()),
|
||||
Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
});
|
||||
if (!Ledger.check()) {
|
||||
Ledger.disconnect();
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(LoginActivity.this,
|
||||
getString(R.string.toast_ledger_start_app, usbDevice.getProductName()),
|
||||
Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
registerDetachReceiver();
|
||||
onLedgerAction();
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(LoginActivity.this,
|
||||
getString(R.string.toast_ledger_attached, usbDevice.getProductName()),
|
||||
Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
|
|
|
@ -134,6 +134,10 @@ public enum Instruction {
|
|||
return value;
|
||||
}
|
||||
|
||||
public byte getByteValue() {
|
||||
return (byte) (value & 0xFF);
|
||||
}
|
||||
|
||||
private int value;
|
||||
|
||||
Instruction(int value) {
|
||||
|
|
|
@ -27,9 +27,11 @@ import com.btchip.BTChipException;
|
|||
import com.btchip.comm.BTChipTransport;
|
||||
import com.btchip.comm.android.BTChipTransportAndroidHID;
|
||||
import com.m2049r.xmrwallet.BuildConfig;
|
||||
import com.m2049r.xmrwallet.model.WalletManager;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
|
@ -40,9 +42,11 @@ public class Ledger {
|
|||
static public final int LOOKAHEAD_SUBADDRESSES = 20;
|
||||
static public final String SUBADDRESS_LOOKAHEAD = LOOKAHEAD_ACCOUNTS + ":" + LOOKAHEAD_SUBADDRESSES;
|
||||
|
||||
private static final byte PROTOCOL_VERSION = 0x02;
|
||||
public static final int SW_OK = 0x9000;
|
||||
public static final int SW_INS_NOT_SUPPORTED = 0x6D00;
|
||||
public static final int OK[] = {SW_OK};
|
||||
public static final int MINIMUM_LEDGER_VERSION = (1 << 16) + (3 << 8) + (1); // 1.3.1
|
||||
|
||||
public static UsbDevice findDevice(UsbManager usbManager) {
|
||||
if (!ENABLED) return null;
|
||||
|
@ -89,6 +93,21 @@ public class Ledger {
|
|||
}
|
||||
}
|
||||
|
||||
static public boolean check() {
|
||||
if (Instance == null) return false;
|
||||
byte[] moneroVersion = WalletManager.moneroVersion().getBytes(StandardCharsets.US_ASCII);
|
||||
|
||||
try {
|
||||
byte[] resp = Instance.exchangeApduNoOpt(Instruction.INS_RESET, moneroVersion, OK);
|
||||
int deviceVersion = (resp[0] << 16) + (resp[1] << 8) + (resp[2]);
|
||||
if (deviceVersion < MINIMUM_LEDGER_VERSION)
|
||||
return false;
|
||||
} catch (BTChipException ex) { // comm error - probably wrong app started on device
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
final private BTChipTransport transport;
|
||||
final private String name;
|
||||
private int lastSW = 0;
|
||||
|
@ -112,7 +131,7 @@ public class Ledger {
|
|||
synchronized private byte[] exchangeRaw(byte[] apdu) {
|
||||
if (transport == null)
|
||||
throw new IllegalStateException("No transport (probably closed previously)");
|
||||
Timber.i("exchangeRaw %02x", apdu[1]);
|
||||
Timber.d("exchangeRaw %02x", apdu[1]);
|
||||
Instruction ins = Instruction.fromByte(apdu[1]);
|
||||
if (listener != null) listener.onInstructionSend(ins, apdu);
|
||||
sniffOut(ins, apdu);
|
||||
|
@ -120,7 +139,6 @@ public class Ledger {
|
|||
if (listener != null) listener.onInstructionReceive(ins, data);
|
||||
sniffIn(data);
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
private byte[] exchange(byte[] apdu) throws BTChipException {
|
||||
|
@ -148,68 +166,19 @@ public class Ledger {
|
|||
throw new BTChipException("Invalid status", lastSW);
|
||||
}
|
||||
|
||||
private byte[] exchangeApdu(byte cla, byte ins, byte p1, byte p2, byte[] data, int acceptedSW[]) throws BTChipException {
|
||||
byte[] apdu = new byte[data.length + 5];
|
||||
apdu[0] = cla;
|
||||
apdu[1] = ins;
|
||||
apdu[2] = p1;
|
||||
apdu[3] = p2;
|
||||
apdu[4] = (byte) (data.length);
|
||||
System.arraycopy(data, 0, apdu, 5, data.length);
|
||||
private byte[] exchangeApduNoOpt(Instruction instruction, byte[] data, int acceptedSW[])
|
||||
throws BTChipException {
|
||||
byte[] apdu = new byte[data.length + 6];
|
||||
apdu[0] = PROTOCOL_VERSION;
|
||||
apdu[1] = instruction.getByteValue();
|
||||
apdu[2] = 0; // p1
|
||||
apdu[3] = 0; // p2
|
||||
apdu[4] = (byte) (data.length + 1); // +1 because the opt byte is part of the data
|
||||
apdu[5] = 0; // opt
|
||||
System.arraycopy(data, 0, apdu, 6, data.length);
|
||||
return exchangeCheck(apdu, acceptedSW);
|
||||
}
|
||||
|
||||
private byte[] exchangeApdu(byte cla, byte ins, byte p1, byte p2, int length, int acceptedSW[]) throws BTChipException {
|
||||
byte[] apdu = new byte[5];
|
||||
apdu[0] = cla;
|
||||
apdu[1] = ins;
|
||||
apdu[2] = p1;
|
||||
apdu[3] = p2;
|
||||
apdu[4] = (byte) (length);
|
||||
return exchangeCheck(apdu, acceptedSW);
|
||||
}
|
||||
|
||||
private byte[] exchangeApduSplit(byte cla, byte ins, byte p1, byte p2, byte[] data, int acceptedSW[]) throws BTChipException {
|
||||
int offset = 0;
|
||||
byte[] result = null;
|
||||
while (offset < data.length) {
|
||||
int blockLength = ((data.length - offset) > 255 ? 255 : data.length - offset);
|
||||
byte[] apdu = new byte[blockLength + 5];
|
||||
apdu[0] = cla;
|
||||
apdu[1] = ins;
|
||||
apdu[2] = p1;
|
||||
apdu[3] = p2;
|
||||
apdu[4] = (byte) (blockLength);
|
||||
System.arraycopy(data, offset, apdu, 5, blockLength);
|
||||
result = exchangeCheck(apdu, acceptedSW);
|
||||
offset += blockLength;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private byte[] exchangeApduSplit2(byte cla, byte ins, byte p1, byte p2, byte[] data, byte[] data2, int acceptedSW[]) throws BTChipException {
|
||||
int offset = 0;
|
||||
byte[] result = null;
|
||||
int maxBlockSize = 255 - data2.length;
|
||||
while (offset < data.length) {
|
||||
int blockLength = ((data.length - offset) > maxBlockSize ? maxBlockSize : data.length - offset);
|
||||
boolean lastBlock = ((offset + blockLength) == data.length);
|
||||
byte[] apdu = new byte[blockLength + 5 + (lastBlock ? data2.length : 0)];
|
||||
apdu[0] = cla;
|
||||
apdu[1] = ins;
|
||||
apdu[2] = p1;
|
||||
apdu[3] = p2;
|
||||
apdu[4] = (byte) (blockLength + (lastBlock ? data2.length : 0));
|
||||
System.arraycopy(data, offset, apdu, 5, blockLength);
|
||||
if (lastBlock) {
|
||||
System.arraycopy(data2, 0, apdu, 5 + blockLength, data2.length);
|
||||
}
|
||||
result = exchangeCheck(apdu, acceptedSW);
|
||||
offset += blockLength;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public interface Listener {
|
||||
void onInstructionSend(Instruction ins, byte[] apdu);
|
||||
|
||||
|
@ -251,7 +220,6 @@ public class Ledger {
|
|||
if (ins == Instruction.INS_GET_KEY) {
|
||||
snoopKey = (apdu[2] == 2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void sniffIn(byte[] data) {
|
||||
|
|
|
@ -354,4 +354,6 @@ public class WalletManager {
|
|||
static public native void logWarning(String category, String message);
|
||||
|
||||
static public native void logError(String category, String message);
|
||||
|
||||
static public native String moneroVersion();
|
||||
}
|
|
@ -379,4 +379,6 @@
|
|||
<string name="prompt_ledger_phrase">Contrasenya Ledger (avançat)</string>
|
||||
<string name="bad_ledger_seed">Llavor de Ledger no vàlida!</string>
|
||||
<string name="prompt_ledger_seed_warn">Introduir la vostra llavor del Ledger aquí té un elevat risc de seguretat!</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -382,4 +382,6 @@
|
|||
<string name="prompt_ledger_phrase">Ledger-Passphrase (optional)</string>
|
||||
<string name="bad_ledger_seed">Ungültiger Ledger-Seed!</string>
|
||||
<string name="prompt_ledger_seed_warn">Deinen Ledger-Seed hier einzugeben, stellt ein erhebliches Sicherheitsrisiko dar!</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -381,4 +381,6 @@
|
|||
<string name="prompt_ledger_phrase">Ledger Passphrase (optional)</string>
|
||||
<string name="bad_ledger_seed">Invalid Ledger Seed!</string>
|
||||
<string name="prompt_ledger_seed_warn">Entering your Ledger Seed here is a major security risk!</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -381,4 +381,6 @@
|
|||
<string name="prompt_ledger_phrase">Ledger Passphrase (optional)</string>
|
||||
<string name="bad_ledger_seed">Invalid Ledger Seed!</string>
|
||||
<string name="prompt_ledger_seed_warn">Entering your Ledger Seed here is a major security risk!</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -371,4 +371,6 @@
|
|||
<string name="prompt_ledger_phrase">Ledger Passphrase (optional)</string>
|
||||
<string name="bad_ledger_seed">Invalid Ledger Seed!</string>
|
||||
<string name="prompt_ledger_seed_warn">Entering your Ledger Seed here is a major security risk!</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -379,4 +379,6 @@
|
|||
<string name="prompt_ledger_phrase">Ledger Passphrase (optional)</string>
|
||||
<string name="bad_ledger_seed">Invalid Ledger Seed!</string>
|
||||
<string name="prompt_ledger_seed_warn">Entering your Ledger Seed here is a major security risk!</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -385,4 +385,6 @@
|
|||
<string name="prompt_ledger_phrase">Mot de passe Ledger (optionnel)</string>
|
||||
<string name="bad_ledger_seed">Phrase mnémonique Ledger invalide !</string>
|
||||
<string name="prompt_ledger_seed_warn">Saisir votre phrase mnémonique Ledger ici est un risque majeur de sécurité !</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -383,4 +383,6 @@
|
|||
<string name="prompt_ledger_phrase">Ledger Passphrase (optional)</string>
|
||||
<string name="bad_ledger_seed">Invalid Ledger Seed!</string>
|
||||
<string name="prompt_ledger_seed_warn">Entering your Ledger Seed here is a major security risk!</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -384,4 +384,6 @@
|
|||
<string name="prompt_ledger_phrase">Frase d\'accesso Ledger (opzionale)</string>
|
||||
<string name="bad_ledger_seed">Seed di Ledger invalido!</string>
|
||||
<string name="prompt_ledger_seed_warn">Inserire il tuo seed di Ledger qui è un grosso rischio!</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -427,4 +427,6 @@
|
|||
<string name="prompt_ledger_phrase">Ledgerパスフレーズ (オプショナル)</string>
|
||||
<string name="bad_ledger_seed">Ledgerのニーモニックシードは不正!</string>
|
||||
<string name="prompt_ledger_seed_warn">ここにLedgerシードを入力するのは、大きなセキュリティリスクですよ!</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -381,4 +381,6 @@
|
|||
<string name="prompt_ledger_phrase">Ledger Passphrase (optional)</string>
|
||||
<string name="bad_ledger_seed">Invalid Ledger Seed!</string>
|
||||
<string name="prompt_ledger_seed_warn">Entering your Ledger Seed here is a major security risk!</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -381,4 +381,6 @@
|
|||
<string name="prompt_ledger_phrase">Ledger Passphrase (optional)</string>
|
||||
<string name="bad_ledger_seed">Invalid Ledger Seed!</string>
|
||||
<string name="prompt_ledger_seed_warn">Entering your Ledger Seed here is a major security risk!</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -373,4 +373,6 @@
|
|||
<string name="prompt_ledger_phrase">Senha da Ledger (opcional)</string>
|
||||
<string name="bad_ledger_seed">Semente da Ledger inválida!</string>
|
||||
<string name="prompt_ledger_seed_warn">Escrever a semente da sua Ledger aqui é um grande risco de segurança!</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -385,4 +385,6 @@
|
|||
<string name="prompt_ledger_phrase">Palavra passe do Ledger (opcional)</string>
|
||||
<string name="bad_ledger_seed">Semente do Ledger invalida!</string>
|
||||
<string name="prompt_ledger_seed_warn">Introduzir a semente do Ledger aqui comporta um elevado risco de segurança!</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -381,4 +381,6 @@
|
|||
<string name="prompt_ledger_phrase">Ledger Passphrase (optional)</string>
|
||||
<string name="bad_ledger_seed">Invalid Ledger Seed!</string>
|
||||
<string name="prompt_ledger_seed_warn">Entering your Ledger Seed here is a major security risk!</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -385,4 +385,6 @@
|
|||
<string name="prompt_ledger_phrase">Пароль Ledger (необязательно)</string>
|
||||
<string name="bad_ledger_seed">Ошибка фразы Ledger!</string>
|
||||
<string name="prompt_ledger_seed_warn">Если вы пытаетесь ввести сюда фразу Ledger, это серьезная угроза для вашей безопасности!</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -382,4 +382,6 @@
|
|||
<string name="prompt_ledger_phrase">Ledger fráza (voliteľné)</string>
|
||||
<string name="bad_ledger_seed">Neplatný Ledger Seed!</string>
|
||||
<string name="prompt_ledger_seed_warn">Vloženie Ledger Seedu sem je vážne bezpečnostné riziko!</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -382,4 +382,5 @@
|
|||
<string name="bad_ledger_seed">Nevalidno seme iz knjige računa!</string>
|
||||
<string name="prompt_ledger_seed_warn">Unošenje tvog semena iz knjige računa na ovom mestu ima veliki sigurnosni rizik!</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -366,4 +366,6 @@
|
|||
<string name="prompt_ledger_phrase">Ledger Passphrase (optional)</string>
|
||||
<string name="bad_ledger_seed">Invalid Ledger Seed!</string>
|
||||
<string name="prompt_ledger_seed_warn">Entering your Ledger Seed here is a major security risk!</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -385,4 +385,6 @@
|
|||
<string name="prompt_ledger_phrase">Ledger Passphrase (optional)</string>
|
||||
<string name="bad_ledger_seed">Invalid Ledger Seed!</string>
|
||||
<string name="prompt_ledger_seed_warn">Entering your Ledger Seed here is a major security risk!</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -303,4 +303,6 @@
|
|||
<string name="prompt_ledger_phrase">Ledger密码(高级模式)</string>
|
||||
<string name="bad_ledger_seed">无效的Ledger种子密语!</string>
|
||||
<string name="prompt_ledger_seed_warn">在此输入您的Ledger种子密语将会产生风险!</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -380,4 +380,6 @@
|
|||
<string name="prompt_ledger_phrase">Ledger 密碼 (選填)</string>
|
||||
<string name="bad_ledger_seed">無效的 Ledger 種子碼!</string>
|
||||
<string name="prompt_ledger_seed_warn">在此輸入 Ledger 種子碼可能存在嚴重的安全風險!</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -432,4 +432,6 @@
|
|||
<string name="prompt_ledger_seed_warn">Entering your Ledger Seed here is a major security risk!</string>
|
||||
|
||||
<string name="label_account" translatable="false">%1$s (%2$s)</string>
|
||||
|
||||
<string name="toast_ledger_start_app">Start Monero App on %1$s</string>
|
||||
</resources>
|
||||
|
|
|
@ -6,4 +6,9 @@
|
|||
product-id="1"
|
||||
vendor-id="11415" />
|
||||
|
||||
<!-- Ledger Nano X HID: VID=0x2C97 PID=0x0004 -->
|
||||
<usb-device
|
||||
product-id="4"
|
||||
vendor-id="11415" />
|
||||
|
||||
</resources>
|
Loading…
Reference in New Issue