1 /* 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 package com.ohos.hapsigntool.utils; 17 18 import com.ohos.hapsigntool.error.CustomException; 19 import com.ohos.hapsigntool.error.ERROR; 20 21 import com.ohos.hapsigntool.error.SignToolErrMsg; 22 import org.bouncycastle.util.encoders.Base64; 23 24 import java.security.Key; 25 import java.security.KeyFactory; 26 import java.security.KeyPair; 27 import java.security.KeyPairGenerator; 28 import java.security.PublicKey; 29 import java.security.PrivateKey; 30 import java.security.NoSuchAlgorithmException; 31 import java.security.spec.InvalidKeySpecException; 32 import java.security.spec.PKCS8EncodedKeySpec; 33 import java.security.spec.X509EncodedKeySpec; 34 35 /** 36 * Key pair relation Class, to create new key pairs. 37 * 38 * @since 2021/12/28 39 */ 40 public final class KeyPairTools { 41 /** 42 * Field RSA. 43 */ 44 public static final String RSA = "RSA"; 45 46 /** 47 * Field EC. 48 */ 49 public static final String ECC = "EC"; 50 51 /** 52 * Field ECC. 53 */ 54 public static final String ECC_INPUT = "ECC"; 55 56 /** 57 * Field RSA_2048. 58 */ 59 public static final int RSA_2048 = 2048; 60 61 /** 62 * Field RSA_3072. 63 */ 64 public static final int RSA_3072 = 3072; 65 66 /** 67 * Field RSA_4096. 68 */ 69 public static final int RSA_4096 = 4096; 70 71 /** 72 * Field NIST_P_256. 73 */ 74 public static final int NIST_P_256 = 256; 75 76 /** 77 * Field NIST_P_384. 78 */ 79 public static final int NIST_P_384 = 384; 80 81 /** 82 * Logger. 83 */ 84 private static final LogUtils LOGGER = new LogUtils(KeyPairTools.class); 85 KeyPairTools()86 private KeyPairTools() {} 87 88 /** 89 * generateKeyPair 90 * 91 * @param algorithm RSA/ECC 92 * @param keySize RSA_2048/3072/4096 NIST_P_256/384 93 * @return Generated keypair 94 */ generateKeyPair(String algorithm, int keySize)95 public static KeyPair generateKeyPair(String algorithm, int keySize) { 96 if (algorithm == null) { 97 CustomException.throwException(ERROR.NOT_SUPPORT_ERROR, SignToolErrMsg.ALGORITHM_NOT_SUPPORT 98 .toString("Not support algorithm: null")); 99 } 100 String alg = algorithm; 101 if (ECC_INPUT.equalsIgnoreCase(alg)) { 102 alg = ECC; 103 } 104 if (RSA.equalsIgnoreCase(alg)) { 105 ValidateUtils.throwIfNotMatches((keySize == RSA_2048 || keySize == RSA_3072 || keySize == RSA_4096), 106 ERROR.NOT_SUPPORT_ERROR, SignToolErrMsg.ALGORITHM_NOT_SUPPORT 107 .toString("Algorithm 'RSA' not support size: " + keySize)); 108 } else if (ECC.equalsIgnoreCase(alg)) { 109 ValidateUtils.throwIfNotMatches((keySize == NIST_P_256 || keySize == NIST_P_384), 110 ERROR.NOT_SUPPORT_ERROR, SignToolErrMsg.ALGORITHM_NOT_SUPPORT 111 .toString("Algorithm 'ECC' not support size: " + keySize)); 112 } else { 113 CustomException.throwException(ERROR.NOT_SUPPORT_ERROR, SignToolErrMsg.ALGORITHM_NOT_SUPPORT 114 .toString("Not support algorithm: " + alg)); 115 } 116 117 try { 118 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(alg); 119 keyPairGenerator.initialize(keySize); 120 return keyPairGenerator.generateKeyPair(); 121 } catch (NoSuchAlgorithmException e) { 122 LOGGER.debug(e.getMessage(), e); 123 CustomException.throwException(ERROR.NOT_SUPPORT_ERROR, SignToolErrMsg.NO_SUCH_SIGNATURE 124 .toString(e.getMessage())); 125 return null; 126 } 127 } 128 129 /** 130 * Convert key to String 131 * 132 * @param key input parameter and key can not be null. 133 * @return return key.getEncoded() in Base64 format. 134 */ key2String(Key key)135 public static String key2String(Key key) { 136 return Base64.toBase64String(key.getEncoded()); 137 } 138 139 /** 140 * Convert string back to key 141 * 142 * @param algorithm input parameter and algorithm can not be null. 143 * @param keyString input parameter and keyString can not be null. 144 * @return return PublicKey. 145 */ stringToPublicKey(String algorithm, String keyString)146 public static PublicKey stringToPublicKey(String algorithm, String keyString) { 147 X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.decode(keyString)); 148 PublicKey result = null; 149 try { 150 result = KeyFactory.getInstance(algorithm).generatePublic(spec); 151 } catch (InvalidKeySpecException | NoSuchAlgorithmException exception) { 152 LOGGER.debug(exception.getMessage(), exception); 153 CustomException.throwException(ERROR.ACCESS_ERROR, SignToolErrMsg.NO_SUCH_SIGNATURE 154 .toString(exception.getMessage())); 155 } 156 return result; 157 } 158 159 /** 160 * Convert string back to key 161 * 162 * @param algorithm input parameter and algorithm can not be null. 163 * @param keyString input parameter and keyString can not be null. 164 * @return return PrivateKey. 165 */ stringToPrivateKey(String algorithm, String keyString)166 public static PrivateKey stringToPrivateKey(String algorithm, String keyString) { 167 PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Base64.decode(keyString)); 168 PrivateKey result = null; 169 try { 170 result = KeyFactory.getInstance(algorithm).generatePrivate(spec); 171 } catch (InvalidKeySpecException | NoSuchAlgorithmException exception) { 172 LOGGER.debug(exception.getMessage(), exception); 173 CustomException.throwException(ERROR.ACCESS_ERROR, SignToolErrMsg.NO_SUCH_SIGNATURE 174 .toString(exception.getMessage())); 175 } 176 return result; 177 } 178 } 179