2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.androidtv.internal.protocol.googletv;
15 import java.math.BigInteger;
16 import java.security.MessageDigest;
17 import java.security.NoSuchAlgorithmException;
18 import java.security.PublicKey;
19 import java.security.cert.Certificate;
20 import java.security.interfaces.RSAPublicKey;
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
27 * GoogleTVCommand represents a GoogleTV protocol command
29 * @author Ben Rosenblum - Initial contribution
32 public class GoogleTVUtils {
33 private static final Logger LOGGER = LoggerFactory.getLogger(GoogleTVUtils.class);
35 private static String processMag(final byte[] magnitude) {
36 final int length = magnitude.length;
38 final BigInteger bigInteger = new BigInteger(1, magnitude);
39 final StringBuilder sb = new StringBuilder();
41 sb.append(length + length);
43 return String.format(sb.toString(), bigInteger);
48 private static final byte[] processDigestArray(final byte[] array) {
52 length = array.length;
53 if (n >= length || array[n] != 0) {
58 final int n2 = length - n;
59 final byte[] array2 = new byte[n2];
60 System.arraycopy(array, n, array2, 0, n2);
64 public static final byte[] processDigest(byte[] digest, Certificate clientCert, Certificate serverCert) {
65 final PublicKey clientPublicKey = clientCert.getPublicKey();
66 final PublicKey serverPublicKey = serverCert.getPublicKey();
68 if (clientPublicKey instanceof RSAPublicKey && serverPublicKey instanceof RSAPublicKey) {
69 final RSAPublicKey clientRSAPublicKey = (RSAPublicKey) clientPublicKey;
70 final RSAPublicKey serverRSAPublicKey = (RSAPublicKey) serverPublicKey;
72 final MessageDigest instance = MessageDigest.getInstance("SHA-256");
73 final byte[] byteArray1 = clientRSAPublicKey.getModulus().abs().toByteArray();
74 final byte[] byteArray2 = clientRSAPublicKey.getPublicExponent().abs().toByteArray();
75 final byte[] byteArray3 = serverRSAPublicKey.getModulus().abs().toByteArray();
76 final byte[] byteArray4 = serverRSAPublicKey.getPublicExponent().abs().toByteArray();
77 final byte[] r1 = processDigestArray(byteArray1);
78 final byte[] r2 = processDigestArray(byteArray2);
79 final byte[] r3 = processDigestArray(byteArray3);
80 final byte[] r4 = processDigestArray(byteArray4);
90 instance.update(digest);
91 digest = instance.digest();
93 } catch (NoSuchAlgorithmException e) {
94 LOGGER.warn("NoSuchAlgorithmException Exception", e);
100 public static String byteArrayToString(byte[] array) {
101 StringBuilder sb = new StringBuilder();
102 for (int i = 0; i < array.length; i++) {
103 sb.append((char) (array[i] & 0xFF));
105 return sb.toString();
108 public static String validatePIN(String pin, Certificate clientCert, Certificate serverCert) {
109 char[] charArray = pin.toCharArray();
111 String s1 = "" + charArray[0] + charArray[1];
112 String s2 = "" + charArray[2] + charArray[3];
113 String s3 = "" + charArray[4] + charArray[5];
114 int si1 = Integer.parseInt(s1, 16);
115 int si2 = Integer.parseInt(s2, 16);
116 int si3 = Integer.parseInt(s3, 16);
118 byte[] sb123 = new byte[] { (byte) si1, (byte) si2, (byte) si3 };
119 byte[] sb23 = new byte[] { (byte) si2, (byte) si3 };
120 byte[] digest = processDigest(sb23, clientCert, serverCert);
121 String digestString = GoogleTVRequest.decodeMessage(byteArrayToString(digest));
123 byte[] validPinB = new byte[] { digest[0], (byte) si2, (byte) si3 };
124 String validPin = GoogleTVRequest.decodeMessage(byteArrayToString(validPinB));
125 LOGGER.trace("validatePIN {} {} {} {} {} {}", sb123, digest[0], sb23, validPinB, validPin, digestString);