1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
|
/*
* Copyright 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.keychain;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import android.content.Context;
import android.util.Base64;
import android.util.Log;
public class SecureWebServer {
// Log tag for this class
private static final String TAG = "SecureWebServer";
// File name of the image used in server response
private static final String EMBEDDED_IMAGE_FILENAME = "training-prof.png";
private SSLServerSocketFactory sssf;
private SSLServerSocket sss;
// A flag to control whether the web server should be kept running
private boolean isRunning = true;
// The base64 encoded image string used as an embedded image
private final String base64Image;
/**
* WebServer constructor.
*/
public SecureWebServer(Context ctx) {
try {
// Get an SSL context using the TLS protocol
SSLContext sslContext = SSLContext.getInstance("TLS");
// Get a key manager factory using the default algorithm
KeyManagerFactory kmf = KeyManagerFactory
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
// Load the PKCS12 key chain
KeyStore ks = KeyStore.getInstance("PKCS12");
FileInputStream fis = ctx.getAssets()
.openFd(KeyChainDemoActivity.PKCS12_FILENAME)
.createInputStream();
ks.load(fis, KeyChainDemoActivity.PKCS12_PASSWORD.toCharArray());
kmf.init(ks, KeyChainDemoActivity.PKCS12_PASSWORD.toCharArray());
// Initialize the SSL context
sslContext.init(kmf.getKeyManagers(), null, null);
// Create the SSL server socket factory
sssf = sslContext.getServerSocketFactory();
} catch (Exception e) {
e.printStackTrace();
}
// Create the base64 image string used in the server response
base64Image = createBase64Image(ctx);
}
/**
* This method starts the web server listening to the port 8080
*/
protected void start() {
new Thread(new Runnable() {
@Override
public void run() {
Log.d(TAG, "Secure Web Server is starting up on port 8080");
try {
// Create the secure server socket
sss = (SSLServerSocket) sssf.createServerSocket(8080);
} catch (Exception e) {
System.out.println("Error: " + e);
return;
}
Log.d(TAG, "Waiting for connection");
while (isRunning) {
try {
// Wait for an SSL connection
Socket socket = sss.accept();
// Got a connection
Log.d(TAG, "Connected, sending data.");
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket
.getOutputStream());
// Read the data until a blank line is reached which
// signifies the end of the client HTTP headers
String str = ".";
while (!str.equals(""))
str = in.readLine();
// Send a HTTP response
out.println("HTTP/1.0 200 OK");
out.println("Content-Type: text/html");
out.println("Server: Android KeyChainiDemo SSL Server");
// this blank line signals the end of the headers
out.println("");
// Send the HTML page
out.println("<H1>Welcome to Android!</H1>");
// Add an embedded Android image
out.println("<img src='data:image/png;base64," + base64Image + "'/>");
out.flush();
socket.close();
} catch (Exception e) {
Log.d(TAG, "Error: " + e);
}
}
}
}).start();
}
/**
* This method stops the SSL web server
*/
protected void stop() {
try {
// Break out from the infinite while loop in start()
isRunning = false;
// Close the socket
if (sss != null) {
sss.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* This method reads a binary image from the assets folder and returns the
* base64 encoded image string.
*
* @param ctx The service this web server is running in.
* @return String The base64 encoded image string or "" if there is an
* exception
*/
private String createBase64Image(Context ctx) {
BufferedInputStream bis;
try {
bis = new BufferedInputStream(ctx.getAssets().open(EMBEDDED_IMAGE_FILENAME));
byte[] embeddedImage = new byte[bis.available()];
bis.read(embeddedImage);
return Base64.encodeToString(embeddedImage, Base64.DEFAULT);
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
}
|