Compare commits

..
Author SHA1 Message Date
Andrea Franz 5a20f8f601 remove default and implementation from interface 2019-11-20 15:38:04 +01:00
9 changed files with 52 additions and 61 deletions
+2 -2
View File
@@ -15,7 +15,7 @@ You can import the SDK in your Gradle or Maven project using [Jitpack.io](https:
```groovy
dependencies {
implementation 'com.github.status-im.status-keycard-java:android:3.0.2'
implementation 'com.github.status-im.status-keycard-java:android:2.2.0'
}
```
@@ -23,6 +23,6 @@ dependencies {
```groovy
dependencies {
implementation 'com.github.status-im.status-keycard-java:desktop:3.0.2'
implementation 'com.github.status-im.status-keycard-java:desktop:2.2.0'
}
```
+2 -2
View File
@@ -8,8 +8,8 @@ android {
defaultConfig {
minSdkVersion 19
targetSdkVersion 28
versionCode 303
versionName "3.0.3"
versionCode 300
versionName "3.0.0"
}
compileOptions {
@@ -34,4 +34,8 @@ public class NFCCardChannel implements CardChannel {
public boolean isConnected() {
return this.isoDep.isConnected();
}
public int pairingPasswordPBKDF2IterationCount() {
return 50000;
}
}
@@ -47,4 +47,8 @@ public class PCSCCardChannel implements CardChannel {
public boolean isConnected() {
return true;
}
public int pairingPasswordPBKDF2IterationCount() {
return 50000;
}
}
@@ -164,9 +164,8 @@ public class KeycardCommandSet {
* Opens the secure channel. Calls the corresponding method of the SecureChannel class.
*
* @throws IOException communication error
* @throws APDUException secure channel error
*/
public void autoOpenSecureChannel() throws IOException, APDUException {
public void autoOpenSecureChannel() throws IOException {
secureChannel.autoOpenSecureChannel(apduChannel);
}
@@ -174,9 +173,8 @@ public class KeycardCommandSet {
* Automatically pairs. Derives the secret from the given password.
*
* @throws IOException communication error
* @throws APDUException pairing error
*/
public void autoPair(String pairingPassword) throws IOException, APDUException {
public void autoPair(String pairingPassword) throws IOException {
byte[] secret = pairingPasswordToSecret(pairingPassword);
secureChannel.autoPair(apduChannel, secret);
@@ -205,9 +203,8 @@ public class KeycardCommandSet {
* Automatically pairs. Calls the corresponding method of the SecureChannel class.
*
* @throws IOException communication error
* @throws APDUException pairing error
*/
public void autoPair(byte[] sharedSecret) throws IOException, APDUException {
public void autoPair(byte[] sharedSecret) throws IOException {
secureChannel.autoPair(apduChannel, sharedSecret);
}
@@ -215,9 +212,8 @@ public class KeycardCommandSet {
* Automatically unpairs. Calls the corresponding method of the SecureChannel class.
*
* @throws IOException communication error
* @throws APDUException unpairing error
*/
public void autoUnpair() throws IOException, APDUException {
public void autoUnpair() throws IOException {
secureChannel.autoUnpair(apduChannel);
}
@@ -258,9 +254,6 @@ public class KeycardCommandSet {
/**
* Unpair all other clients.
*
* @throws IOException communication error
* @throws APDUException unpairing error
*/
public void unpairOthers() throws IOException, APDUException {
secureChannel.unpairOthers(apduChannel);
@@ -118,14 +118,24 @@ public class SecureChannelSession {
* @param apduChannel the apdu channel
* @throws IOException communication error
*/
public void autoOpenSecureChannel(CardChannel apduChannel) throws IOException, APDUException {
public void autoOpenSecureChannel(CardChannel apduChannel) throws IOException {
APDUResponse response = openSecureChannel(apduChannel, pairing.getPairingIndex(), publicKey);
if (response.getSw() != 0x9000) {
throw new IOException("OPEN SECURE CHANNEL failed");
}
processOpenSecureChannelResponse(response);
response = mutuallyAuthenticate(apduChannel);
response.checkOK("MUTUALLY AUTHENTICATE failed");
verifyMutuallyAuthenticateResponse(response);
if (response.getSw() != 0x9000) {
throw new IOException("MUTUALLY AUTHENTICATE failed");
}
if(!verifyMutuallyAuthenticateResponse(response)) {
throw new IOException("Invalid authentication data from the card");
}
}
/**
@@ -158,10 +168,8 @@ public class SecureChannelSession {
* @param response the card response
* @return true if response is correct, false otherwise
*/
public void verifyMutuallyAuthenticateResponse(APDUResponse response) throws APDUException {
if (response.getData().length != SC_SECRET_LENGTH) {
throw new APDUException("Invalid authentication data from the card");
}
public boolean verifyMutuallyAuthenticateResponse(APDUResponse response) {
return response.getData().length == SC_SECRET_LENGTH;
}
/**
@@ -170,10 +178,14 @@ public class SecureChannelSession {
* @param apduChannel the apdu channel
* @throws IOException communication error
*/
public void autoPair(CardChannel apduChannel, byte[] sharedSecret) throws IOException, APDUException {
public void autoPair(CardChannel apduChannel, byte[] sharedSecret) throws IOException {
byte[] challenge = new byte[32];
random.nextBytes(challenge);
APDUResponse resp = pair(apduChannel, PAIR_P1_FIRST_STEP, challenge).checkOK("Pairing failed on step 1");
APDUResponse resp = pair(apduChannel, PAIR_P1_FIRST_STEP, challenge);
if (resp.getSw() != 0x9000) {
throw new IOException("Pairing failed on step 1");
}
byte[] respData = resp.getData();
byte[] cardCryptogram = Arrays.copyOf(respData, 32);
@@ -192,13 +204,18 @@ public class SecureChannelSession {
checkCryptogram = md.digest(challenge);
if (!Arrays.equals(checkCryptogram, cardCryptogram)) {
throw new APDUException("Invalid card cryptogram");
throw new IOException("Invalid card cryptogram");
}
md.update(sharedSecret);
checkCryptogram = md.digest(cardChallenge);
resp = pair(apduChannel, PAIR_P1_LAST_STEP, checkCryptogram).checkOK("Pairing failed on step 2");
resp = pair(apduChannel, PAIR_P1_LAST_STEP, checkCryptogram);
if (resp.getSw() != 0x9000) {
throw new IOException("Pairing failed on step 2");
}
respData = resp.getData();
md.update(sharedSecret);
pairing = new Pairing(md.digest(Arrays.copyOfRange(respData, 1, respData.length)), respData[0]);
@@ -210,8 +227,12 @@ public class SecureChannelSession {
* @param apduChannel the apdu channel
* @throws IOException communication error
*/
public void autoUnpair(CardChannel apduChannel) throws IOException, APDUException {
unpair(apduChannel, pairing.getPairingIndex()).checkOK("Unpairing failed");
public void autoUnpair(CardChannel apduChannel) throws IOException {
APDUResponse resp = unpair(apduChannel, pairing.getPairingIndex());
if (resp.getSw() != 0x9000) {
throw new IOException("Unpairing failed");
}
}
/**
@@ -61,7 +61,7 @@ public class Crypto {
} catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException e) {
throw new RuntimeException("error generating session keys.", e);
} catch (NoSuchProviderException e) {
throw new RuntimeException("BouncyCastle not installed");
throw new RuntimeException("SpongyCastle not installed");
}
}
@@ -88,35 +88,6 @@ public class APDUResponse {
}
}
/**
* Asserts that the SW is 0x9000. Throws an exception with the given message if it isn't
*
* @param message the error message
* @return this object, to simplify chaining
* @throws APDUException if the SW is not 0x9000
*/
public APDUResponse checkOK(String message) throws APDUException {
return checkSW(message, SW_OK);
}
/**
* Asserts that the SW is contained in the given list. Throws an exception with the given message if it isn't.
*
* @param message the error message
* @param codes the list of SWs to match.
* @return this object, to simplify chaining
* @throws APDUException if the SW is not 0x9000
*/
public APDUResponse checkSW(String message, int... codes) throws APDUException {
for (int code : codes) {
if (this.sw == code) {
return this;
}
}
throw new APDUException(this.sw, message);
}
/**
* Checks response from an authentication command (VERIFY PIN, UNBLOCK PUK)
*
@@ -29,7 +29,5 @@ public interface CardChannel {
*
* @return the iteration count
*/
default int pairingPasswordPBKDF2IterationCount() {
return 50000;
}
int pairingPasswordPBKDF2IterationCount();
}