HTTPS Server on Android Device Using NanoHttpd

前端 未结 4 722
忘掉有多难
忘掉有多难 2021-02-01 11:04

I am trying to run an HTTPS Server on an Android device using NanoHttpd (my final goal is to run WSS server on Android). I successfully ran HTTP Server and Websocket using NanoH

相关标签:
4条回答
  • 2021-02-01 11:28

    Modified from Decoded's solution since I was not able to use JKS type of keystore.

    Instead I use Keystore Explorer to generate a BKS key. Select BKS-V1 as type of the new KeyStore, then setup the NanoHTTPD server before start:

    androidWebServer = new AndroidWebServer(port);
    
    File f = new File("src/main/resources/localkey.bks");
    System.setProperty("javax.net.ssl.trustStore", f.getAbsolutePath());
    androidWebServer.setServerSocketFactory(new AndroidWebServer.SecureServerSocketFactory(AndroidWebServer.makeSSLSocketFactory("/" + f.getName(), "yourKeyStorePass".toCharArray()), null));
    
    androidWebServer.start(); 
    
    0 讨论(0)
  • 2021-02-01 11:37

    After Hours of toil, I've got it!

    Here is MY (working) code:

    // I placed this block right below my class declaration so it runs
    // as soon as the class is defined. (this is for localhost testing ONLY!!!!)    
    static {
        //for localhost testing only
        javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
        new javax.net.ssl.HostnameVerifier(){
    
            public boolean verify(String hostname,
                    javax.net.ssl.SSLSession sslSession) {
                if (hostname.equals("localhost")) {
                    return true;
                }
                return false;
            }
        });
    }
    
    // then in an init function, I set it all up here
    this.secureAppServer = new NanoHTTPD(9043);
    File f =new File("src/main/resources/key001.jks");
    System.setProperty("javax.net.ssl.trustStore", f.getAbsolutePath());
    this.secureAppServer.setServerSocketFactory(new SecureServerSocketFactory(NanoHTTPD.makeSSLSocketFactory("/" +f.getName(), "myawesomepassword".toCharArray()), null));
    
    this.secureAppServer.start();
    

    Here is the actual NanoHttpd Test case which illustrates exactly how its done Nano style.

    package fi.iki.elonen;
    
    import java.io.File;
    
    /*
     * #%L
     * NanoHttpd-Core
     * %%
     * Copyright (C) 2012 - 2015 nanohttpd
     * %%
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     * 
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     * 
     * 2. Redistributions in binary form must reproduce the above copyright notice,
     *    this list of conditions and the following disclaimer in the documentation
     *    and/or other materials provided with the distribution.
     * 
     * 3. Neither the name of the nanohttpd nor the names of its contributors
     *    may be used to endorse or promote products derived from this software without
     *    specific prior written permission.
     * 
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
     * OF THE POSSIBILITY OF SUCH DAMAGE.
     * #L%
     */
    
    import java.io.IOException;
    import java.util.Arrays;
    
    import javax.net.ssl.SSLServerSocket;
    
    import org.apache.http.HttpEntity;
    import org.apache.http.HttpResponse;
    import org.apache.http.client.ClientProtocolException;
    import org.apache.http.client.methods.HttpTrace;
    import org.apache.http.impl.client.DefaultHttpClient;
    import org.junit.After;
    import org.junit.Assert;
    import org.junit.Before;
    import org.junit.Test;
    
    import fi.iki.elonen.NanoHTTPD.SecureServerSocketFactory;
    
    public class SSLServerSocketFactoryTest extends HttpServerTest {
    
        @Test
        public void testSSLConnection() throws ClientProtocolException, IOException {
            DefaultHttpClient httpclient = new DefaultHttpClient();
            HttpTrace httphead = new HttpTrace("https://localhost:9043/index.html");
            HttpResponse response = httpclient.execute(httphead);
            HttpEntity entity = response.getEntity();
            Assert.assertEquals(200, response.getStatusLine().getStatusCode());
    
            Assert.assertEquals(9043, this.testServer.getListeningPort());
            Assert.assertTrue(this.testServer.isAlive());
        }
    
        @Test
        public void testCreatePassesTheProtocolsToServerSocket() throws IOException {
            // first find the supported protocols
            SecureServerSocketFactory secureServerSocketFactory = new SecureServerSocketFactory(NanoHTTPD.makeSSLSocketFactory("/keystore.jks", "password".toCharArray()), null);
            SSLServerSocket socket = (SSLServerSocket) secureServerSocketFactory.create();
            String[] protocols = socket.getSupportedProtocols();
    
            // remove one element from supported protocols
            if (protocols.length > 0) {
                protocols = Arrays.copyOfRange(protocols, 0, protocols.length - 1);
            }
    
            // test
            secureServerSocketFactory = new SecureServerSocketFactory(NanoHTTPD.makeSSLSocketFactory("/keystore.jks", "password".toCharArray()), protocols);
            socket = (SSLServerSocket) secureServerSocketFactory.create();
            Assert.assertArrayEquals("Enabled protocols specified in the factory were not set to the socket.", protocols, socket.getEnabledProtocols());
        }
    
        @Before
        public void setUp() throws Exception {
            System.setProperty("javax.net.ssl.trustStore", new File("src/test/resources/keystore.jks").getAbsolutePath());
            this.testServer = new TestServer(9043);
            this.testServer.setServerSocketFactory(new SecureServerSocketFactory(NanoHTTPD.makeSSLSocketFactory("/keystore.jks", "password".toCharArray()), null));
            this.tempFileManager = new TestTempFileManager();
            this.testServer.start();
            try {
                long start = System.currentTimeMillis();
                Thread.sleep(100L);
                while (!this.testServer.wasStarted()) {
                    Thread.sleep(100L);
                    if (System.currentTimeMillis() - start > 2000) {
                        Assert.fail("could not start server");
                    }
                }
            } catch (InterruptedException e) {
            }
        }
    
        @After
        public void tearDown() {
            this.testServer.stop();
        }
    }
    
    0 讨论(0)
  • 2021-02-01 11:41

    This link has solution: https://www.baeldung.com/nanohttpd#https

    use keytool generate jks

    keytool -genkey -keyalg RSA -alias selfsigned
      -keystore keystore.jks -storepass your_password -validity 360
      -keysize 2048 -ext SAN=DNS:localhost,IP:127.0.0.1  -validity 9999
    

    move keystore.jks to project src/main/resources

    and use following code:

    public class HttpsExample  extends NanoHTTPD {
     
        public HttpsExample() throws IOException {
            super(8080);
            makeSecure(NanoHTTPD.makeSSLSocketFactory(
              "/keystore.jks", "password".toCharArray()), null);
            start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);
        }
     
        // main and serve methods
    }
    
    0 讨论(0)
  • 2021-02-01 11:55

    The other answers didn't work for me. I had to create a BKS-V1 Keystore using a KeyStore Explorer and save it to android assets folder as "keystore.bks". Alternatively, You can also use the following code to make the KeyStore file then just open it using KeyStore Explorer and change its type to BKS-V1.

    keytool -genkey -keyalg RSA -alias selfsigned -keystore keystore.bks -storepass myKeyStorePass -validity 360 -keysize 2048 -ext SAN=DNS:localhost,IP:127.0.0.1  -validity 9999 
    

    I used the following code to make it work.

    package com.example.myappname
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.security.KeyStore;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;
    import java.security.UnrecoverableKeyException;
    import java.security.cert.CertificateException;
    
    import javax.net.ssl.KeyManagerFactory;
    
    import fi.iki.elonen.NanoHTTPD;
    
    public class Server extends NanoHTTPD {
        public Server(int port) throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException {
            super(port);
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            InputStream keyStoreStream = context.get().getAssets().open("keystore.bks");
            keyStore.load(keyStoreStream, "myKeyStorePass".toCharArray());
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(keyStore, "myCertificatePass".toCharArray());
            makeSecure(NanoHTTPD.makeSSLSocketFactory(keyStore, keyManagerFactory), null);
        }
    
        @Override
        public Response serve(IHTTPSession session) {
        }
    }
    

    To use it just write the following code and you will have an HTTPS server running on your Android device.

    Server server = new Server(8080);
    server.start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);
    

    This code is made possible thanks to the example provided in the following Github issue comment.

    https://github.com/NanoHttpd/nanohttpd/issues/535#issuecomment-479269044

    0 讨论(0)
提交回复
热议问题