Open Keychain 개발자 매뉴얼


Contents

1. Instroduction and Target

2. Supporting Environment

3. Prepare Open Keychain

3.1 Server
3.2 Client

4. Start Open Keychain with Sample

4.1 Guide
4.2 How to Use
4.2.1 Register
4.2.2 Authenticate
4.2.3 Discard
4.3 Sample

5. Open Keychain API

5.1 Server
5.2 Client
5.3 Common API

6. Fingerprint Keychain

6.1 Install

6.2 Usage

6.2.1 Check Availability

6.2.2 Register

6.2.3 Use

6.3 Error Handling


1. Introduction and Target

This document is written for clients to hope to establish Open Keychain in a new or existing service. Contents in this document is written for a customer who can understand programming and services using SDK. Before reading this document, you may need to understand what is Blockchain, Web Application Server, Application, Transport Layer Security, HTTPS, Certificate sign & verification.

2. Supporting Environment

  • Client
    • Android
    • iOS
    • Web Browser (Javascript)
  • Server
    • Java
      • Tomcat
      • Jeus
      • WAS supporting Java

3. Prepare Open Keychain

3.1. Server

  • Install Coinstack SDK, OpenKeychain library, and WAS

3.2. Client

  • Android
    • need to append a jar file.
  • iOS
    1. Check ruby. If you can't check a version, please install Ruby at first.

      ruby -v

    2. Check gem. If you can't check a version, please install Gem at first.

      gem -v

    3. Install CocoaPods

      sudo gem install cocoapods

    4. Create CocoaPods Podfile for a project dependencies and library

4. Start Open Keychain with Sample

4.1 Guide

Server and Client communicate with Challenge and Sign for certification and registration. Check a generated event exactly in this process to distinguish Server and Client.

4.2 How to User

4.2.1 Register
  1. Client -> Server | Request Challenge
  2. Server | Certificate Challenge
  3. Client | After success to certificate, create and save a public key and private key, create a response with the private key for the Challenge
  4. Client -> Server | Send the response
  5. Server | Certificate the response
  6. Server | After success to certificate, register Blockchain
4.2.2 Authenticate
  1. Client -> Server | Request Challenge
  2. Server | Certificate Challenge
  3. Client | After success to certificate, create a response with the private key for the Challenge
  4. Client -> Server | Send the response
  5. Server | Certificate the response
  6. Server | After success to certificate, login
4.2.3 Discard
  1. Conduct typical authentication process. (ID/Password, SMS, phone, credit card, public certification, etc.)
  2. After success to certificate, discard the certificate.
4.3 Sample
Java
import static org.junit.Assert.*;

import java.io.IOException;

import org.junit.*;

import io.blocko.apache.commons.codec.binary.Base64;
import io.blocko.coinstack.CoinStackClient;
import io.blocko.coinstack.ECKey;
import io.blocko.coinstack.exception.CoinStackException;
import io.blocko.coinstack.openkeychain.KeyManager;
import io.blocko.coinstack.openkeychain.client.LoginManager;
import io.blocko.coinstack.openkeychain.model.Challenge;
import io.blocko.coinstack.openkeychain.model.RegistrationMetadata;
import io.blocko.coinstack.openkeychain.model.Response;
import io.blocko.coinstack.openkeychain.server.AuthorizationManager;
import io.blocko.coinstack.openkeychain.server.ChallengeResponseManager;
import io.blocko.coinstack.openkeychain.server.RegistrationManager;

public class TestAuth {
    public static String generateRandomContextString() {
        return ECKey.createNewPrivateKey();
    }

    public static String loadClientKeyForTest() {
        return ECKey.createNewPrivateKey();
    }

    private CoinStackClient coinstack = null;
    private KeyManager keyManager = null;

    private CoinStackClient clientCoinStack = null;
    private KeyManager clientKeyManager = null;

    @Before
    public void before() throws Exception {
        // [server]
        String privateKey = ECKey.createNewPrivateKey();
        String authAddress = ECKey.deriveAddress(privateKey);
        coinstack = new CoinStackClient(new CredentialsProvider() {
            @Override
            public String getAccessKey() {
                return ""; // coinstack api key
            }
            @Override
            public String getSecretKey() {
                return "";
            }
        }, Endpoint.MAINNET);

        keyManager = initKeyManager(privateKey);
        if (!CoinStackManager.checkValidKeyPair(keyManager)) {
            throw new RuntimeException("invalid server key");
        }

        // [client]
        clientCoinStack = new CoinStackClient(new CredentialsProvider() {
            @Override
            public String getAccessKey() {
                return ""; // coinstack api key
            }
            @Override
            public String getSecretKey() {
                return "";
            }
        }, Endpoint.MAINNET);

       String clientPrivateKey = loadClientKeyForTest();
       clientKeyManager = initKeyManager(clientPrivateKey);
        System.out.println("[client] authAddress="+clientKeyManager.fetchAddress()+" / privateKey="+clientPrivateKey);
    }

    @Test
    public void testRegistration() throws Exception {
        // [server] prepare regManager
        String SERVER_AUTH_ADDRESS = keyManager.fetchAddress();
        ChallengeResponseManager regManager = new RegistrationManager(coinstack, keyManager);

        // [client] prepare loginManager
        String CLIENT_AUTH_ADDRESS = clientKeyManager.fetchAddress();
        LoginManager clientLoginManager = new LoginManager(clientCoinStack, clientKeyManager);

        // [client] send request to server
        System.out.println("[client] request");

        // [server] create challenge and send to client
        String CHALLENGE_CONTEXT = generateRandomContextString();
        Challenge challenge = regManager.createChallenge(CHALLENGE_CONTEXT);
        System.out.println("[server] create challenge context: "+CHALLENGE_CONTEXT);
        System.out.println("[server] send challenge: "+challenge.marshal());

        // [client] check challenge
        System.out.println("[client] received challenge context: "+challenge.getContext());
        assertTrue(clientLoginManager.checkChallenge(challenge, SERVER_AUTH_ADDRESS));
        System.out.println("[client] check challenge: success");

        // [client] create response and send to server
        Response response = clientLoginManager.createResponse(challenge);
        System.out.println("[client] send response: "+response.marshal());

        // [server] check response
        String buf = new String(Base64.decodeBase64(response.getChallenge()));
        Challenge clientReceived = Challenge.unmarshal(buf);
        System.out.println("[server] received response context: "+clientReceived.getContext());
        assertTrue(regManager.checkResponse(CHALLENGE_CONTEXT, response));
        System.out.println("[server] check response: success");

        // [server] record
        // WARNING: use BTC
        testRegistration(response.getCertificate());

        // [server] check
        testSignin(CLIENT_AUTH_ADDRESS, response.getCertificate());

        // [server] revoke
        // WARNING: use BTC
        testRevocation(CLIENT_AUTH_ADDRESS, response.getCertificate());
    }

    public void testRegistration(String certificateAddress) throws IOException {
        RegistrationManager regManager = new RegistrationManager(coinstack, keyManager);
        RegistrationMetadata metadata = new RegistrationMetadata() {
            @Override
            public byte[] marshal() {
                return "METADATA".getBytes();
            }
        };
        System.out.println("[server] registration metadata: "+new String(metadata.marshal()));

        String txId = regManager.recordRegistration(certificateAddress, metadata);
        System.out.println("[server] registration txId: "+txId);
    }

    public void testSignin(String clientAuthAddress, String certificateAddress) throws IOException, CoinStackException {
        if (clientAuthAddress == null || !clientAuthAddress.equals(certificateAddress)) {
            System.out.println("[server] signin: fail, invalid authAddress");
            return;
        }
        AuthorizationManager authManager = new AuthorizationManager(coinstack, keyManager);
        byte[] metadata = authManager.checkRegistration(certificateAddress);
        if (metadata == null) {
            System.out.println("[server] signin: fail.");
        }
        else {
            System.out.println("[server] signin: success.");
            System.out.println("[server] signin metadata: "+new String(metadata));
        }
    }

    public void testRevocation(String clientAuthAddress, String certificateAddress) throws IOException {
        if (clientAuthAddress == null || !clientAuthAddress.equals(certificateAddress)) {
            System.out.println("[server] revocation: fail, invalid authAddress");
            return;
        }
        RegistrationManager regManager = new RegistrationManager(coinstack, keyManager);
        String txId = regManager.revokeRegistration(certificateAddress);
        System.out.println("[server] revocation txId: "+txId);
    }

    public static KeyManager initKeyManager(String privateKey, String authAddress) {
        KeyManager keyManager = new InMemoryKeyManager();
        keyManager.registerKey(authAddress, privateKey.toCharArray());
        return keyManager;
    }
}

5. Open Keychain API

5.1 Server API

Class RegistrationManager
Constructor
RegistrationManager(CoinStackClient client, KeyManager keyManager)
Method
Challenge createChallenge(String context) - Create Challenge
boolean checkResponse(Response response) - Client side: certificate Challenge
boolean checkResponse(String context, Response response) - Client side: certificate Challenge
String recordRegistration(String certificateAddress, RegistrationMetadata metadata) - Register authentication transaction in Blockchain
String revokeRegistration(String certificateAddress) - Register discrad transaction in Blockchain
Class Challenge
Constructor
Static use
Method
String marshal() - Show Challenge in a readable string
static Challenge unmarshal(String serialized) - **
Class AuthorizationManager
Constructor
AuthorizationManager(CoinStackClient client, KeyManager keyManager)
Method
byte[] checkRegistration(String certificateAddress) - Certificate status of registration

5.2 Client API

  • Android | Class LoginManager | | -- | | Constructor | | LoginManager(CoinStackClient client, KeyManager keyManager) | | | | Method | | boolean checkChallenge(Challenge challenge, String authorityAddress) - Certificate Challenge from Server | | Response createResponse(Challenge challenge) - Create Challenge response |

  • iOS | @interface OpenKeyChainLib : NSObject | |--| | -(BOOL) checkChallenge:(NSString*)challenge authorityAddress:(NSString*)authorityAddress; - Certificate Challnge from Server | | -(NSString*) createResponse:(NSString*)challenge privateKey:(NSString*)privateKey; - Create Challenge response |

5.3 Common API

  • Java | Class ECKey | | -- | | Constructor | | Static use | | | | Method | | String createNewPrivateKey() - Create new private key | | String deriveAddress(String createdNewPrivateKey) - Generate public key |
Class InMemoryKeyManager
Constructor
InMemoryKeyManager()
Method
void registerKey(String address, char[] privateKey) - Initialize key manager
  • iOS | @interface OpenKeyChainLib : NSObject | |--| | -(NSString*)createPrivateKey; - Create new private key | | -(NSString*) deriveAddress:(NSString*)privateKey; - Generate public key |

6. Fingerprint Keychain

6.1 Install

6.2 Usage

6.2.1 Check Availability

  • Android

    FingerprintKey.isAvailable(
     function(res){
         if (!res.isAvailable) {
             // Can't use Fingerprint.
         }
    
         if (!res.isHardwareDetected) {
             // Can't fint H/W.
         }
    
         if (res.hasEnrolledFingerprints) {
             // Fingerprint already exist.
         }
     },
     function(res){
         // Error
         console.log(res);
     );
    
  • iOS

    FingerprintKey.isAvailable(
     function(res){
         if (!res.isAvailable) {
             // Can't use Fingerprint.
         }
    
         if (!res.isHardwareDetected) {
             // Can't fint H/W.
         }
    
         if (!res.hasEnrolledFingerprints) {
             // Fingerprint already exist.
         }
     },
     function(res){
         // Error
         console.log(res);
     });
    

6.2.2 Register

  • Android

    FingerprintKey.initKey(
     {
         keyId: "testKey", // unique key
         locale: {
             desc:"desc",
             cancel:"cancel",
             title:"title",
             hint:"hint",
             success:"success",
             notrecognized:"notrecognized"
         }
     },
     function(res){
         if (res.status == "ok") {
             // Create response with res.key
         } else if (res.status == "cancelled") {
             // User cancel
         } else if (res.status == "error") {
             // Error
         }
     },
     function(res){
         // Error
         console.log(res);
     });
    
  • iOS

    FingerprintKey.initKey(
     {
         keyId: "testKey", // unique key
         message: "message to show"
     },
     function(res){
         if (res.status == "ok") {
             // Create response with res.key
         } else if (res.status == "cancelled") {
             // User cancel
         } else if (res.status == "error") {
             // Error
         }
     },
     function(res){
         // Error
         console.log(res);
     });
    

6.2.3 Use

  • Android

    FingerprintKey.fetchKey(
     {
         keyId: "testKey", // unique key
         locale: {
             desc:"desc",
             cancel:"cancel",
             title:"title",
             hint:"hint",
             success:"success",
             notrecognized:"notrecognized"
         }
     },
     function(res){
         if (res.status == "ok") {
             // Create response with res.key
         } else if (res.status == "cancelled") {
             // User cancel
         } else if (res.status == "error") {
             // Error.
          }
     },
     function(res){
         // Error.
         console.log(res);
     });
    
  • iOS

    FingerprintKey.fetchKey(
     {
         keyId: "testKey", // unique key
         message: "Message to show"
     },
     function(res){
         if (res.status == "ok") {
             // Create response with res.key
         } else if (res.status == "cancelled") {
             // User cancel
         } else if (res.status == "error") {
             // Error.
          }
     },
     function(res){
         // Error.
         console.log(res);
     });
    

6.3 Error Handling

  • When res.status == "error", return res.error object.
Error Code
FingerprintKey.errors.TOO_MANY_TRIES
Lock becuase too much try
FingerprintKey.errors.KEY_NOT_FOUND
Try without key registration
FingerprintKey.errors.FINGERPRINT_NOT_AVAILABLE
Fingerprint is unavailable
FingerprintKey.fetchKey(
    {
        keyId: "testKey", // unique key
        message: "Message to show"
    },
    function(res){
        if (res.status == "error") {
            // Error: too much try
            if (res.error == FingerprintKey.errors.TOO_MANY_TRIES) {
                console.log(res.error.code);
                console.log(res.error.message);
                console.log(res.cause);
            }
            // Error: miss key registration
            else if (res.error == FingerprintKey.errors.KEY_NOT_FOUND) {
                console.log(res.error.code);
                console.log(res.error.message);
                console.log(res.cause);
            }
            // Error: unavailable
            else if (res.error == FingerprintKey.errors.FINGERPRINT_NOT_AVAILABLE) {
                console.log(res.error.code);
                console.log(res.error.message);
                console.log(res.cause);
            }
        }
    },
    function(res){
        // Error
        console.log(res);
    });

results matching ""

    No results matching ""