view src/com/five_ten_sg/connectbot/service/AuthAgentService.java @ 320:5afb8c1a54b9
ganymed
add ecdsa key support everywhere
author |
Carl Byington <carl@five-ten-sg.com> |
date |
Thu, 31 Jul 2014 08:36:33 -0700 (2014-07-31) |
parents |
c1f929cb3dd0 |
children |
b40bc65fa09a |
line source
package com.five_ten_sg.connectbot.service;
import java.io.IOException;
import java.security.SecureRandom;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import com.five_ten_sg.connectbot.service.TerminalManager;
import com.five_ten_sg.connectbot.service.TerminalManager.KeyHolder;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.madgag.ssh.android.authagent.AndroidAuthAgent;
import ch.ethz.ssh2.signature.DSASHA1Verify;
import ch.ethz.ssh2.signature.ECDSASHA2Verify;
import ch.ethz.ssh2.signature.RSASHA1Verify;
public class AuthAgentService extends Service {
private static final String TAG = "ConnectBot.AuthAgentService";
protected TerminalManager manager;
final Lock lock = new ReentrantLock();
final Condition managerReady = lock.newCondition();
private ServiceConnection connection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
Log.d(TAG, "Terminal manager available! Hurrah");
manager = ((TerminalManager.TerminalBinder) service).getService();
lock.lock();
try {
managerReady.signal();
}
finally {
lock.unlock();
}
}
public void onServiceDisconnected(ComponentName className) {
manager = null;
Log.d(TAG, "Terminal manager gone...");
}
};
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind() called");
bindService(new Intent(this, TerminalManager.class), connection, BIND_AUTO_CREATE);
return mBinder;
}
private final AndroidAuthAgent.Stub mBinder = new AndroidAuthAgent.Stub() {
public Map getIdentities() throws RemoteException {
Log.d(TAG, "getIdentities() called");
waitForTerminalManager();
Log.d(TAG, "getIdentities() manager.loadedKeypairs : " + manager.loadedKeypairs);
return sshEncodedPubKeysFrom(manager.loadedKeypairs);
}
public byte[] sign(byte[] publicKey, byte[] data) throws RemoteException {
Log.d(TAG, "sign() called");
waitForTerminalManager();
KeyPair pair = keyPairFor(publicKey);
Log.d(TAG, "sign() - signing keypair found : " + pair);
if (pair == null) {
return null;
}
PrivateKey privKey = pair.getPrivate();
if (privKey instanceof RSAPrivateKey) {
return sshEncodedSignatureFor(data, (RSAPrivateKey) privKey);
}
else if (privKey instanceof DSAPrivateKey) {
return sshEncodedSignatureFor(data, (DSAPrivateKey) privKey);
}
else if (privKey instanceof ECPrivateKey) {
return sshEncodedSignatureFor(data, (ECPrivateKey) privKey);
}
return null;
}
private void waitForTerminalManager() throws RemoteException {
lock.lock();
try {
while (manager == null) {
Log.d(TAG, "Waiting for TerminalManager...");
managerReady.await();
}
}
catch (InterruptedException e) {
throw new RemoteException();
}
finally {
lock.unlock();
}
Log.d(TAG, "Got TerminalManager : " + manager);
}
private Map<String, byte[]> sshEncodedPubKeysFrom(Map<String, KeyHolder> keypairs) {
Map<String, byte[]> pubkeys = new HashMap<String, byte[]> (keypairs.size());
for (Entry<String, KeyHolder> entry : keypairs.entrySet()) {
byte[] encodedKey = sshEncodedPubKeyFrom(entry.getValue().pair);
if (encodedKey != null) {
pubkeys.put(entry.getKey(), encodedKey);
}
}
return pubkeys;
}
private byte[] sshEncodedPubKeyFrom(KeyPair pair) {
try {
PrivateKey privKey = pair.getPrivate();
if (privKey instanceof RSAPrivateKey) {
RSAPublicKey pubkey = (RSAPublicKey)pair.getPublic();
return RSASHA1Verify.encodeSSHRSAPublicKey(pubkey);
}
else if (privKey instanceof DSAPrivateKey) {
DSAPublicKey pubkey = (DSAPublicKey)pair.getPublic();
return DSASHA1Verify.encodeSSHDSAPublicKey(pubkey);
}
else if (privKey instanceof ECPrivateKey) {
ECPublicKey pubkey = (ECPublicKey) pair.getPublic();
return ECDSASHA2Verify.encodeSSHECDSAPublicKey(pubkey);
}
}
catch (IOException e) {
Log.e(TAG, "Couldn't encode " + pair, e);
}
return null;
}
private byte[] sshEncodedSignatureFor(byte[] data, RSAPrivateKey privKey) {
try {
byte[] signature = RSASHA1Verify.generateSignature(data, privKey);
return RSASHA1Verify.encodeSSHRSASignature(signature);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
private byte[] sshEncodedSignatureFor(byte[] data, DSAPrivateKey privKey) {
try {
byte[] signature = DSASHA1Verify.generateSignature(data, privKey, new SecureRandom());
return DSASHA1Verify.encodeSSHDSASignature(signature);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
private byte[] sshEncodedSignatureFor(byte[] data, ECPrivateKey privKey) {
try {
byte[] signature = ECDSASHA2Verify.generateSignature(data, privKey);
return ECDSASHA2Verify.encodeSSHECDSASignature(signature, privKey.getParams());
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
private KeyPair keyPairFor(byte[] publicKey) {
String nickname = manager.getKeyNickname(publicKey);
if (nickname == null) {
Log.w(TAG, "No key-pair found for public-key.");
return null;
}
// check manager.loadedKeypairs.get(nickname).bean.isConfirmUse() and promptForPubkeyUse(nickname) ?
return manager.getKey(nickname);
}
};
}