2017-11-14 5 views
2

現在、Google Cloud IoT Coreに接続するためのAndroid関連のプログラムに関する作業を行っています。私はGoogleが提供しているMavenコードをサンプルし、Gradleのためにそれを修正しました(すべての輸入物を含む)。チェックのすべての種類を行った後、いつでも私はそれがこのエラー私が想定していた秘密鍵ファイルは、JWTのために使用することを私に言ってCloud Iotコアのjava.io.FileNotFoundExceptionコード

W/System.err: java.io.FileNotFoundException: com/example/adityaprakash/test/rsa_private.pem (No such file or directory) 

に与え続けるアンドロイド物事を実行しているラズベリーPI3でプログラムを実行しようとしていますそれがないという事実にもかかわらず存在していないと私は、PEM file.Hereのパスを与えている私のJavaコード

ある
package com.example.adityaprakash.test; 

import android.support.v7.app.AppCompatActivity; 
import android.os.Bundle; 
import android.util.Log; 

public class MainActivity extends AppCompatActivity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     //setContentView(R.layout.activity_main); 
     Log.i("#########","######"); 
     MqttExample mqtt = new MqttExample(); 
     try { 
      mqtt.Start(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

MqttExample.java

package com.example.adityaprakash.test; 
// [END cloudiotcore_mqtt_imports] 
import org.eclipse.paho.client.mqttv3.MqttClient; 
import org.eclipse.paho.client.mqttv3.MqttConnectOptions; 
import org.eclipse.paho.client.mqttv3.MqttMessage; 
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; 

import org.joda.time.DateTime; 

import java.io.BufferedReader; 
import java.io.FileReader; 

import java.security.KeyFactory; 
import java.security.spec.PKCS8EncodedKeySpec; 

import android.util.Base64; 

import io.jsonwebtoken.JwtBuilder; 
import io.jsonwebtoken.Jwts; 
import io.jsonwebtoken.SignatureAlgorithm; 

public class MqttExample { 

    // [START cloudiotcore_mqtt_createjwt] 
    /** Create a Cloud IoT Core JWT for the given project id, signed with the given RSA key. */ 
    public static String createJwtRsa(String projectId, String privateKeyFile) throws Exception { 
     DateTime now = new DateTime(); 

     String strKeyPEM = ""; 
     BufferedReader br = new BufferedReader(new FileReader(privateKeyFile)); 
     String line; 
     while ((line = br.readLine()) != null) { 
      strKeyPEM += line + "\n"; 
     } 
     br.close(); 
     // Create a JWT to authenticate this device. The device will be disconnected after the token 
     // expires, and will have to reconnect with a new token. The audience field should always be set 
     // to the GCP project id. 
     JwtBuilder jwtBuilder = 
       Jwts.builder() 
         .setIssuedAt(now.toDate()) 
         .setExpiration(now.plusMinutes(20).toDate()) 
         .setAudience(projectId); 
     String privateKeyPEM = strKeyPEM; 
     privateKeyPEM = privateKeyPEM.replace("-----BEGIN PRIVATE KEY-----\n", ""); 
     privateKeyPEM = privateKeyPEM.replace("-----END PRIVATE KEY-----", ""); 
     byte[] encoded = Base64.decode(privateKeyPEM,Base64.DEFAULT); 
     PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(encoded); 
     KeyFactory kf = KeyFactory.getInstance("RSA"); 

     return jwtBuilder.signWith(SignatureAlgorithm.RS256, kf.generatePrivate(spec)).compact(); 
    } 


    /** Parse arguments, configure MQTT, and publish messages. */ 
    public void Start() throws Exception { 
     // [START cloudiotcore_mqtt_configuremqtt] 
     MqttExampleOptions options = MqttExampleOptions.values(); 
     if (options == null) { 
      // Could not parse. 
      System.exit(1); 
     } 
     // Build the connection string for Google's Cloud IoT Core MQTT server. Only SSL 
     // connections are accepted. For server authentication, the JVM's root certificates 
     // are used. 
     final String mqttServerAddress = 
       String.format("ssl://%s:%s", options.mqttBridgeHostname, options.mqttBridgePort); 

     // Create our MQTT client. The mqttClientId is a unique string that identifies this device. For 
     // Google Cloud IoT Core, it must be in the format below. 
     final String mqttClientId = 
       String.format(
         "projects/%s/locations/%s/registries/%s/devices/%s", 
         options.projectId, options.cloudRegion, options.registryId, options.deviceId); 

     MqttConnectOptions connectOptions = new MqttConnectOptions(); 
     // Note that the the Google Cloud IoT Core only supports MQTT 3.1.1, and Paho requires that we 
     // explictly set this. If you don't set MQTT version, the server will immediately close its 
     // connection to your device. 
     connectOptions.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1); 

     // With Google Cloud IoT Core, the username field is ignored, however it must be set for the 
     // Paho client library to send the password field. The password field is used to transmit a JWT 
     // to authorize the device. 
     connectOptions.setUserName("unused"); 

     System.out.println(options.algorithm); 
     if (options.algorithm.equals("RS256")) { 
      connectOptions.setPassword(
        createJwtRsa(options.projectId, options.privateKeyFile).toCharArray()); 
     }else { 
      throw new IllegalArgumentException(
        "Invalid algorithm " + options.algorithm + ". Should be one of 'RS256' or 'ES256'."); 
     } 
     // [END cloudiotcore_mqtt_configuremqtt] 

     // [START cloudiotcore_mqtt_publish] 
     // Create a client, and connect to the Google MQTT bridge. 
     MqttClient client = new MqttClient(mqttServerAddress, mqttClientId, new MemoryPersistence()); 
     try { 
      client.connect(connectOptions); 

      // Publish to the events or state topic based on the flag. 
      String subTopic = options.messageType.equals("event") ? "events" : options.messageType; 

      // The MQTT topic that this device will publish telemetry data to. The MQTT topic name is 
      // required to be in the format below. Note that this is not the same as the device registry's 
      // Cloud Pub/Sub topic. 
      String mqttTopic = String.format("/devices/%s/%s", options.deviceId, subTopic); 

      // Publish numMessages messages to the MQTT bridge, at a rate of 1 per second. 
      for (int i = 1; i <= options.numMessages; ++i) { 
       String payload = String.format("%s/%s-payload number-%d", options.registryId, options.deviceId, i); 
       System.out.format(
         "Publishing %s message %d/%d: '%s'\n", 
         options.messageType, i, options.numMessages, payload); 

       // Publish "payload" to the MQTT topic. qos=1 means at least once delivery. Cloud IoT Core 
       // also supports qos=0 for at most once delivery. 
       MqttMessage message = new MqttMessage(payload.getBytes()); 
       message.setQos(1); 
       client.publish(mqttTopic, message); 

       if (options.messageType.equals("event")) { 
        // Send telemetry events every second 
        Thread.sleep(1000); 
       } 
       else { 
        // Note: Update Device state less frequently than with telemetry events 
        Thread.sleep(5000); 
       } 
      } 
     } finally { 
      // Disconnect the client and finish the run. 
      client.disconnect(); 
     } 
     System.out.println("Finished loop successfully. Goodbye!"); 
     // [END cloudiotcore_mqtt_publish] 
    } 

} 

とMqttExa mpleOptions.javaコード:

package com.example.adityaprakash.test; 

public class MqttExampleOptions { 
    String projectId; 
    String registryId; 
    String deviceId; 
    String privateKeyFile; 
    String algorithm; 
    String cloudRegion; 
    int numMessages; 
    String mqttBridgeHostname; 
    short mqttBridgePort; 
    String messageType; 

    /** Construct an MqttExampleOptions class. */ 
    public static MqttExampleOptions values() { 

     try { 

      MqttExampleOptions res = new MqttExampleOptions(); 

      res.projectId = "_"; 
      res.registryId = "_"; 
      res.deviceId = "_"; 
      res.privateKeyFile = "com/example/adityaprakash/test/rsa_private.pem"; 
      res.algorithm = "RS256"; 
      res.cloudRegion = "asia-east1"; 
      res.numMessages = 100; 
      res.mqttBridgeHostname = "mqtt.googleapis.com"; 
      res.mqttBridgePort = 8883; 
      res.messageType = "event"; 
      return res; 

     } catch (Exception e) { 
      System.err.println(e.getMessage()); 
      return null; 
     } 
    } 
} 

誰でもこの問題を解決することができます。
P.私はコードが完全に馬鹿に見えることを知っています。私はAndroidプログラミングの経験がないので、それを行かせてください。

+0

あなたのファイルは存在しますが、読み込み権限がありません.pemファイルに許可を与えます –

答えて

2

ファイルI/Oを正しく実行していないことは間違いありません。あなたのファイル"com/example/adityaprakash/test/rsa_private.pem"は、デバイス上の実際のファイルパスに対応していません。デバイス上のファイルの場所は、プロジェクト内の場所と異なる場合があります。あなたのファイルが実際にどこにあるのかを決定する必要があります。

+0

私はadb pushを使用してrsa_private_pkcs8ファイルをAndroidのsdcardの任意のディレクトリに配置し、それは変数の完全なパスです、それは正しく動作するはずですか? – Aditya

+0

はい、ファイルパスは使用している文字列と一致する必要があります。 –

1

AndroidThingsでは、Androidリソースで認証情報を提供する方が簡単です。これがどのように機能するかは、my fork of the WeatherStation sampleを参照してください。

次/生privatekey.txt

まず、アプリに(例えばrsa_private_pkcs8)秘密鍵ファイルをコピー/ srcに/メイン/ resを/、あなたにあなたのJWTを計算するために使用されるキーを読み込むことができます

Context mContext; 
int resIdPk = getResources().getIdentifier("privatekey", "raw", getPackageName());  

... 

InputStream privateKey = mContext.getResources().openRawResource(resIdPk); 
byte[] keyBytes = inputStreamToBytes(privateKey); 
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); 
KeyFactory kf = KeyFactory.getInstance("EC"); 

最後に、pkcs8形式ではないファイルを参照しているように見えます。これはJavaに問題を引き起こします。 Android(Java)で資格情報を開くときは、PKCS8にパッケージ化されているキーを使用してください。

3

あなたがフォローしている例は、Android用に設計されていません。

res.privateKeyFile = "com/example/adityaprakash/test/rsa_private.pem";

Androidのファイルシステム上の同じディレクトリに関連しています。http://blog.blundellapps.co.uk/tut-google-cloud-iot-core-mqtt-on-android/

あなたは(/rawディレクトリに行くあなたのpemファイル付き)この

のようなセットアップ通信をすることができます:私はここにクラウドのIoTコアに話をする方法の AndroidThings説明を書いた


// Setup the communication with your Google IoT Core details 
     communicator = new IotCoreCommunicator.Builder() 
       .withContext(this) 
       .withCloudRegion("your-region") // ex: europe-west1 
       .withProjectId("your-project-id") // ex: supercoolproject23236 
       .withRegistryId("your-registry-id") // ex: my-devices 
       .withDeviceId("a-device-id") // ex: my-test-raspberry-pi 
       .withPrivateKeyRawFileId(R.raw.rsa_private) 
       .build(); 

ソースコードはこちらhttps://github.com/blundell/CloudIoTCoreMQTTExample


上記は、安全な環境またはエンドツーエンドのテストのために十分です。しかし、生産IoTデバイスをリリースしたい場合は、ROMにPEMを埋め込み、プライベートファイルストレージアクセスを使用します。 https://developer.android.com/training/articles/keystore.html

この例は、ここで見つけることができます:https://github.com/androidthings/sensorhub-cloud-iot

具体的に、このクラス:

https://github.com/androidthings/sensorhub-cloud-iot/blob/e50bde0100fa81818ebbadb54561b3b68ccb64b8/app/src/main/java/com/example/androidthings/sensorhub/cloud/cloudiot/MqttAuthentication.java

あなたは、その後生成し、デバイス上のPEMを使用することができます。

public Certificate getCertificate() { 
    KeyStore ks = KeyStore.getInstance("AndroidKeyStore"); 
    ks.load(null); 

    certificate = ks.getCertificate("Cloud IoT Authentication"); 
    if (certificate == null) { 
     Log.w(TAG, "No IoT Auth Certificate found, generating new cert"); 
     generateAuthenticationKey(); 
     certificate = ks.getCertificate(keyAlias); 
    } 
    Log.i(TAG, "loaded certificate: " + keyAlias); 
} 

および

private void generateAuthenticationKey() throws GeneralSecurityException { 
     KeyPairGenerator kpg = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore"); 
     kpg.initialize(new KeyGenParameterSpec.Builder("Cloud IoT Authentication",KeyProperties.PURPOSE_SIGN) 
     .setKeySize(2048) 
     .setCertificateSubject(new X500Principal("CN=unused")) 
     .setDigests(KeyProperties.DIGEST_SHA256) 
    .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1) 
     .build()); 

     kpg.generateKeyPair(); 
    } 
関連する問題