Mercurial > 510Connectbot
diff src/com/five_ten_sg/connectbot/service/AuthAgentService.java @ 0:0ce5cc452d02
initial version
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Thu, 22 May 2014 10:41:19 -0700 |
parents | |
children | 91a31873c42a |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/five_ten_sg/connectbot/service/AuthAgentService.java Thu May 22 10:41:19 2014 -0700 @@ -0,0 +1,176 @@ +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 com.trilead.ssh2.signature.DSASHA1Verify; +import com.trilead.ssh2.signature.ECDSASHA2Verify; +import com.trilead.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); + } + + 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); + } + } + 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 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); + } + }; +}