RSA/AES Question

Not an expert at this - hoping someone with a better background can help. I’m trying to implement this: https://pro-bravia.sony.net/develop/integrate/rest-api/doc/Data-Encryption_401146660/index.html. Please note in the beginning paragraph that a 128-bit AES-CBC key is required.

Right now - I call getPublicKey on the device to get the public key. I create my common key and encrypt it with the public key - then call getTextForm({ encKey: xxx }) to get the current text encrypted with my AES key. However, the getTextForm is failing with 40002 Encryption Failed (which at the bottom of the article says it’s a key issue.

Here is the quick code I’m using to test the call out with:

			// sony key returned from getPublicKey call
			String sonyKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzXy876n9F+mUkjcoYmnNAqf8d/n0oqO7Qb8bzHyS5VVVfPjEl6SfrmC18jGWPoapRNUZTHKkJjbZT3np24cw6VtMLrw40OMPx9vMWygRJO/gXErDYy/BoXzkbrs3BqZ9O1qJH+5DfB/M5Dp+tYK6+qhCrQKMV9I9YDQ6lZ1ppxl7CaKlMeV80Km1dExTfxYZb5G27AiwGoIeC2UI7DWmDlghZf5dMR6uf6u1VXfyhklt2vAno3BxylSKX3xztDaSFDM1Q7oQZcAcup/k3JyuQbJG03vsJo39TQKZqnq2r9FuSkvNueXrBElRjnZN26LHIGLSpk7WBL/JnF6Vl4Ho0QIDAQAB";
			
			// Create an RSA public key from the above sonyKey
	        byte[] byteKey = Base64.getDecoder().decode(sonyKey.getBytes());
	        X509EncodedKeySpec X509publicKey = new X509EncodedKeySpec(byteKey);
	        KeyFactory kf = KeyFactory.getInstance("RSA");
	        PublicKey sonyPublicKey = kf.generatePublic(X509publicKey);

			// Generate our secret (common) key - 128bits
			KeyGenerator gen = KeyGenerator.getInstance("AES");
			gen.init(128); /* 128-bit AES */
			SecretKey secretKey = gen.generateKey();
			
			// Encrypt our secret key to encKey (doesn't say but assume base64)
	        Cipher cipher = Cipher.getInstance("RSA");
	        cipher.init(Cipher.ENCRYPT_MODE, sonyPublicKey);
	        byte[] a = cipher.doFinal(secretKey.getEncoded());
	        String encKey = Base64.getEncoder().encodeToString(a);

The above run’s fine and produces an encKey - but I get a 40002 from the sony tv when I try to use it. Anybody see any issues?

Note: the article is very light on details. I don’t know if an init vector is needed (and if it’s included in the encKey) and I’m assuming it should be base64 encoded…

Any help would be great…
Tim

This line looks suspicious to me. Is the public key call returning a String or a byte array? If it returns a String, use the string variant of the decode method. Have a look at the docs, it uses ISO_8859_1 for interpreting the String bytes, while your code (String.getBytes()) uses your platform default charset, which might be UTF-8.
Don’t know, if this will fix it, though.

Thanks for the hint - I’ll try that later today

Just tried it - same thing

OK, another thing: from the sample in the docs for getPublicKey and getTextForm you can see that the parameters are definitely Base64 encoded strings (you can tell by the two equal-signs ("=") at the end).
What I’m missing in your sample are the actual API calls, I’d be really interested in seeing them.
Your “sonyKey” doesn’t have the base64 equal-signs at the end (which at least for the decoding shouldn’t matter), but the resulting byte array is 294 bytes long, while the keys from the documentation samples are 277 (might be from a different device, but double check the base64 string is correct).

Something else to try might be in the cipher initialization: Be explicit about the padding (try “RSA/ECB/PKCS1Padding”) - again, should be default, but you might be hitting this problem.
(I don’t know anything about the device - is it by any chance Android based?)

EDIT: for the AES key this is not an issue here, since you are only generating a key which the device will use - the block mode and padding parameters are only relevant when you deal with actual data to en/decrypt.

I don’t see any obvious issue in the rest of the code.

I know for a fact the sonykey is correct (both from a base64 and rsa standpoint - the RSA parsing of the key throws an error otherwise). As you pointed out - I’m pretty sure it has to do with padding and I have tried that (along with every variation I can think of) - unfortunately their document is quite lite on the RSA specs needed (beyond pointing to the RFC).

For your info:

13-Jan-2020 08:13:05.523 [DEBUG] [org.openhab.binding.sony.internal.net.HttpRequest ] - 1 * Sending client request on thread qtp744249996-3598
1 > POST http://192.168.1.104/sony/encryption
1 > Accept: application/json
1 > Connection: close
1 > Content-Type: application/json
1 > User-Agent: OpenHab/Sony/Binding
1 > X-CERS-DEVICE-ID: MediaRemote:00-11-22-33-44-55
1 > X-CERS-DEVICE-INFO: OpenHab/Sony/Binding
{"id":100,"method":"getPublicKey","version":"1.0","params":[]}

13-Jan-2020 08:13:05.543 [DEBUG] [org.openhab.binding.sony.internal.net.HttpRequest ] - 1 * Client response received on thread qtp744249996-3598
1 < 200
1 < Connection: close
1 < content: application/json
1 < Content-Length: 432
{"result":[{"publicKey":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAupBvxCnUC4k64fCi6LochZqdY+zFg12pt6pDFuoZ6xFVLdPXrtsYm4LaBxDn2NtFYNjPqlbPeUl5UoMcbwo+5GyfCKtwWYwq7k0iECr9VeLDm+FG0QpAA+zitQVUhFyAA5dFSfMSqg6q+hR257DkmhzCZFHQTpt35OLh6B1zivmhm5UUpbVpIwGO4nlY65qwSLKma72Qyy3A0aijFw0soTLoB+NP8e7xOm+rV\/kBbIouRvF3CCOIeC52zaDZeKg4U0XdjUDYq4Nl\/2soAzDhmyEzl8UmUXfxCnw7Lbi95OdiF1+X9PD7vYRQ84grLxck+hHAFAoMZdX0OSODRVLrdQIDAQAB"}],"id":100}

Then…

13-Jan-2020 08:13:05.547 [DEBUG] [binding.sony.internal.transports.SonyHttpTransport] - Closing http client
13-Jan-2020 08:16:57.303 [DEBUG] [ab.binding.sony.internal.transports.SonyAuthFilter] - Trying to renew our authorization cookie
13-Jan-2020 08:16:57.538 [DEBUG] [ab.binding.sony.internal.transports.SonyAuthFilter] - Authorization cookie was renewed
13-Jan-2020 08:16:57.550 [DEBUG] [org.openhab.binding.sony.internal.net.HttpRequest ] - 1 * Sending client request on thread qtp744249996-351
1 > POST http://192.168.1.104/sony/appControl
1 > Accept: application/json
1 > Connection: close
1 > Content-Type: application/json
1 > User-Agent: OpenHab/Sony/Binding
1 > X-CERS-DEVICE-ID: MediaRemote:00-11-22-33-44-55
1 > X-CERS-DEVICE-INFO: OpenHab/Sony/Binding
{"id":100,"method":"getTextForm","version":"1.1","params":[{"encKey":"dkOqz6Vd0wC5UqwrNlNYan5HmeXzUSt1CKyeaXBF/5IhtD3wdMBvedmWXxpNr+L4PZCdSPPZAOtK9SQ6YVL5M1nDkAf8buCj9+jHo17J8tJ5BIOQztB3JtMyJbn10c+THsIaWRobAiB6T8dFAwZIY/zGEf0ZdvLO2OhKfywgOzukw/HzTAdIbIUCjg7iaBT75Ipy6x4HZomeYHcNI1Tk1VpqxhPxyqNeLM+VDuV9Dnwdy0JsLDLyuCUd9fStifnMA3+wwSEHJAao91gUHkGXYFRP/iGskw2tMQd/IanCncSWWnYacx09+tL6/prsBvm0Z9BA1W6fAIoe6PPD0clGTg=="}]}

13-Jan-2020 08:16:57.720 [DEBUG] [org.openhab.binding.sony.internal.net.HttpRequest ] - 1 * Client response received on thread qtp744249996-351
1 < 200
1 < Connection: close
1 < content: application/json
1 < Content-Length: 46
{"error":[40002,"Encryption Failed"],"id":100}

How have you gone with this? I am also trying to implement this ( although in c#), but having exactly the same problem. On the SONY api website it says the common key is in the format AES-Key “:” AES-IV . So what i am doing is generating my AES key and IV as 128bit CBC keys (so they are 16 bytes long each). Then adding a hex 3A in between making a 33 byte long string which is then encoded using the RSA public key i get from getPublicKey. I am getting either encrytion failed 40002 if OAEP padding is set to true and internal server error 500 if OAEP padding is set to false.

Have you gotten any further? I’ve sent Sony an email about this.