From 5c4e08c05d4e8781ac9609a09fb762cf60da285e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=9F=922012?= <345849402@qq.com> Date: Wed, 12 Sep 2018 18:03:26 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=8A=A0=E5=AF=86=E7=AE=97?= =?UTF-8?q?=E6=B3=95(AES=E3=80=81DES=E3=80=81RSA=E3=80=81SHA=E3=80=81Base6?= =?UTF-8?q?4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 5 + .../seckill/common/encrypt/Base64Encoder.java | 33 +++ .../seckill/common/encrypt/EncrypSHA.java | 32 +++ .../seckill/common/encrypt/MD5Util.java | 69 +++++ .../seckill/common/encrypt/SecurityAES.java | 236 ++++++++++++++++++ .../common/encrypt/SecurityBase64.java | 49 ++++ .../seckill/common/encrypt/SecurityDES.java | 93 +++++++ .../seckill/common/encrypt/SecurityRSA.java | 121 +++++++++ .../service/impl/SeckillServiceImpl.java | 5 + 9 files changed, 643 insertions(+) create mode 100644 src/main/java/com/itstyle/seckill/common/encrypt/Base64Encoder.java create mode 100644 src/main/java/com/itstyle/seckill/common/encrypt/EncrypSHA.java create mode 100644 src/main/java/com/itstyle/seckill/common/encrypt/MD5Util.java create mode 100644 src/main/java/com/itstyle/seckill/common/encrypt/SecurityAES.java create mode 100644 src/main/java/com/itstyle/seckill/common/encrypt/SecurityBase64.java create mode 100644 src/main/java/com/itstyle/seckill/common/encrypt/SecurityDES.java create mode 100644 src/main/java/com/itstyle/seckill/common/encrypt/SecurityRSA.java diff --git a/pom.xml b/pom.xml index aff049f..fd2c6fd 100644 --- a/pom.xml +++ b/pom.xml @@ -111,6 +111,11 @@ guava 25.1-jre + + commons-codec + commons-codec + 1.11 + spring-boot-seckill diff --git a/src/main/java/com/itstyle/seckill/common/encrypt/Base64Encoder.java b/src/main/java/com/itstyle/seckill/common/encrypt/Base64Encoder.java new file mode 100644 index 0000000..28ed47f --- /dev/null +++ b/src/main/java/com/itstyle/seckill/common/encrypt/Base64Encoder.java @@ -0,0 +1,33 @@ +package com.itstyle.seckill.common.encrypt; + +public class Base64Encoder { + public static String getBASE64(String s) { + if (s == null) + return null; + return (new sun.misc.BASE64Encoder()).encode(s.getBytes()); + } + // 将 BASE64 编码的字符串 s 进行解码 解密 + public static String getFromBASE64(String s) { + if (s == null) + return null; + sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder(); + try { + byte[] b = decoder.decodeBuffer(s); + return new String(b); + } catch (Exception e) { + return null; + } + } + public static String mTOa(Object ming){ + return Base64Encoder.getBASE64(Base64Encoder.getBASE64(Base64Encoder.getBASE64((String)ming))); + } + public static String aTOm(String an){ + return Base64Encoder.getFromBASE64(Base64Encoder.getFromBASE64(Base64Encoder.getFromBASE64(an))); + } + public static void main(String[] args) { + String a = mTOa("爪哇笔记".toString()); + System.out.println(a);//加密 + System.out.println(aTOm(a));//解密 + } + +} diff --git a/src/main/java/com/itstyle/seckill/common/encrypt/EncrypSHA.java b/src/main/java/com/itstyle/seckill/common/encrypt/EncrypSHA.java new file mode 100644 index 0000000..96e6c7c --- /dev/null +++ b/src/main/java/com/itstyle/seckill/common/encrypt/EncrypSHA.java @@ -0,0 +1,32 @@ +package com.itstyle.seckill.common.encrypt; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class EncrypSHA { + + public byte[] eccrypt(String info) throws NoSuchAlgorithmException{ + MessageDigest md5 = MessageDigest.getInstance("SHA"); + byte[] srcBytes = info.getBytes(); + //使用srcBytes更新摘要 + md5.update(srcBytes); + //完成哈希计算,得到result + byte[] resultBytes = md5.digest(); + return resultBytes; + } + + /** + * @param args + * @throws NoSuchAlgorithmException + */ + public static void main(String[] args) throws NoSuchAlgorithmException { + String msg = "爪哇笔记"; + EncrypSHA sha = new EncrypSHA(); + byte[] resultBytes = sha.eccrypt(msg); + System.out.println("明文是:" + msg); + System.out.println("密文是:" + new String(resultBytes)); + + } + +} + diff --git a/src/main/java/com/itstyle/seckill/common/encrypt/MD5Util.java b/src/main/java/com/itstyle/seckill/common/encrypt/MD5Util.java new file mode 100644 index 0000000..0c03e6e --- /dev/null +++ b/src/main/java/com/itstyle/seckill/common/encrypt/MD5Util.java @@ -0,0 +1,69 @@ +package com.itstyle.seckill.common.encrypt; + +import java.security.MessageDigest; + + +public class MD5Util { + + // MD5加码。32位 + public static String MD5(String inStr) { + MessageDigest md5 = null; + try { + md5 = MessageDigest.getInstance("MD5"); + } catch (Exception e) { + System.out.println(e.toString()); + e.printStackTrace(); + return ""; + } + char[] charArray = inStr.toCharArray(); + byte[] byteArray = new byte[charArray.length]; + + for (int i = 0; i < charArray.length; i++) + byteArray[i] = (byte) charArray[i]; + + byte[] md5Bytes = md5.digest(byteArray); + + StringBuffer hexValue = new StringBuffer(); + + for (int i = 0; i < md5Bytes.length; i++) { + int val = ((int) md5Bytes[i]) & 0xff; + if (val < 16) + hexValue.append("0"); + hexValue.append(Integer.toHexString(val)); + } + + return hexValue.toString(); + } + + // 可逆的加密算法 + public static String KL(String inStr) { + char[] a = inStr.toCharArray(); + for (int i = 0; i < a.length; i++) { + a[i] = (char) (a[i] ^ 't'); + } + String s = new String(a); + return s; + } + + // 加密后解密 + public static String JM(String inStr) { + char[] a = inStr.toCharArray(); + for (int i = 0; i < a.length; i++) { + a[i] = (char) (a[i] ^ 't'); + } + String k = new String(a); + return k; + } + + // 测试主函数 + public static void main(String args[]) { + String s = new String("123456"); + System.out.println("原始:" + s); + System.out.println("MD5后:" + MD5(s)); + System.out.println("MD5后再加密:" + KL(MD5(s))); + System.out.println("解密为MD5后的:" + JM(KL(MD5(s)))); + System.out.println("加密的:" + KL(s)); + System.out.println("解密的:" + JM(KL(s))); + } + +} diff --git a/src/main/java/com/itstyle/seckill/common/encrypt/SecurityAES.java b/src/main/java/com/itstyle/seckill/common/encrypt/SecurityAES.java new file mode 100644 index 0000000..9a6a426 --- /dev/null +++ b/src/main/java/com/itstyle/seckill/common/encrypt/SecurityAES.java @@ -0,0 +1,236 @@ +package com.itstyle.seckill.common.encrypt; +import java.io.UnsupportedEncodingException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.KeyGenerator; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import org.apache.commons.codec.binary.Base64; +/** + * AES对称加密 + * 创建者 张志朋 + * 创建时间 2017年11月22日 + * + */ +public class SecurityAES { + private final static String encoding = "UTF-8"; + private static String PASSWORD = "qwedcxza"; + + + /** + * AES加密 + * @Author 张志朋 + * @param content + * @param password + * @return String + * @Date 2015年2月7日 + * 更新日志 + * 2015年2月7日 张志朋 首次创建 + * + */ + public static String encryptAES(String content) { + byte[] encryptResult = encrypt(content); + String encryptResultStr = parseByte2HexStr(encryptResult); + // BASE64位加密 + encryptResultStr = ebotongEncrypto(encryptResultStr); + return encryptResultStr; + } + /** + * AES解密 + * @Author 张志朋 + * @param encryptResultStr + * @param password + * @return String + * @Date 2015年2月7日 + * 更新日志 + * 2015年2月7日 张志朋 首次创建 + * + */ + public static String decrypt(String encryptResultStr) { + // BASE64位解密 + String decrpt = ebotongDecrypto(encryptResultStr); + byte[] decryptFrom = parseHexStr2Byte(decrpt); + byte[] decryptResult = decrypt(decryptFrom); + return new String(decryptResult); + } + /** + * 加密字符串 + * @Author 张志朋 + * @param str + * @return String + * @Date 2015年2月7日 + * 更新日志 + * 2015年2月7日 张志朋 首次创建 + * + */ + public static String ebotongEncrypto(String str) { + String result = str; + if (str != null && str.length() > 0) { + try { + byte[] encodeByte = str.getBytes(encoding); + //阿里巴巴 + //result = Base64.byteArrayToBase64(encodeByte); + result = new String(Base64.encodeBase64(encodeByte),"Utf-8"); + } catch (Exception e) { + e.printStackTrace(); + } + } + //base64加密超过一定长度会自动换行 需要去除换行符 + return result.replaceAll("\r\n", "").replaceAll("\r", "").replaceAll("\n", ""); + } + /** + * 解密字符串 + * @Author 张志朋 + * @param str + * @return String + * @Date 2015年2月7日 + * 更新日志 + * 2015年2月7日 张志朋 首次创建 + * + */ + public static String ebotongDecrypto(String str) { + try { + //byte[] encodeByte = Base64.base64ToByteArray(str);//阿里巴巴 + byte[] encodeByte = Base64.decodeBase64(str.getBytes("Utf-8")); + + return new String(encodeByte); + } catch (Exception e) { + e.printStackTrace(); + return str; + } + } + /** + * 加密 + * @Author 张志朋 + * @param content + * @param password + * @return byte[] + * @Date 2015年2月7日 + * 更新日志 + * 2015年2月7日 张志朋 首次创建 + * + */ + private static byte[] encrypt(String content) { + try { + KeyGenerator kgen = KeyGenerator.getInstance("AES"); + //防止linux下 随机生成key + SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" ); + secureRandom.setSeed(PASSWORD.getBytes()); + kgen.init(128, secureRandom); + SecretKey secretKey = kgen.generateKey(); + byte[] enCodeFormat = secretKey.getEncoded(); + SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); + Cipher cipher = Cipher.getInstance("AES");// 创建密码器 + byte[] byteContent = content.getBytes("utf-8"); + cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化 + byte[] result = cipher.doFinal(byteContent); + return result; // 加密 + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (NoSuchPaddingException e) { + e.printStackTrace(); + } catch (InvalidKeyException e) { + e.printStackTrace(); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } catch (IllegalBlockSizeException e) { + e.printStackTrace(); + } catch (BadPaddingException e) { + e.printStackTrace(); + } + return null; + } + /** + * 解密 + * @Author 张志朋 + * @param content + * @param password + * @return byte[] + * @Date 2015年2月7日 + * 更新日志 + * 2015年2月7日 张志朋 首次创建 + * + */ + private static byte[] decrypt(byte[] content) { + try { + KeyGenerator kgen = KeyGenerator.getInstance("AES"); + //防止linux下 随机生成key + SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" ); + secureRandom.setSeed(PASSWORD.getBytes()); + kgen.init(128, secureRandom); + SecretKey secretKey = kgen.generateKey(); + byte[] enCodeFormat = secretKey.getEncoded(); + SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); + Cipher cipher = Cipher.getInstance("AES");// 创建密码器 + cipher.init(Cipher.DECRYPT_MODE, key);// 初始化 + byte[] result = cipher.doFinal(content); + return result; // 加密 + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (NoSuchPaddingException e) { + e.printStackTrace(); + } catch (InvalidKeyException e) { + e.printStackTrace(); + } catch (IllegalBlockSizeException e) { + e.printStackTrace(); + } catch (BadPaddingException e) { + e.printStackTrace(); + } + return null; + } + /** + * 将二进制转换成16进制 + * @Author 张志朋 + * @param buf + * @return String + * @Date 2015年2月7日 + * 更新日志 + * 2015年2月7日 张志朋 首次创建 + * + */ + public static String parseByte2HexStr(byte buf[]) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < buf.length; i++) { + String hex = Integer.toHexString(buf[i] & 0xFF); + if (hex.length() == 1) { + hex = '0' + hex; + } + sb.append(hex.toUpperCase()); + } + return sb.toString(); + } + /** + * 将16进制转换为二进制 + * @Author 张志朋 + * @param hexStr + * @return byte[] + * @Date 2015年2月7日 + * 更新日志 + * 2015年2月7日 张志朋 首次创建 + * + */ + public static byte[] parseHexStr2Byte(String hexStr) { + if (hexStr.length() < 1) + return null; + byte[] result = new byte[hexStr.length()/2]; + for (int i = 0;i< hexStr.length()/2; i++) { + int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16); + int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16); + result[i] = (byte) (high * 16 + low); + } + return result; + } + public static void main(String[] args) { + String str = encryptAES("1234567890"); + System.out.println(str); + str = decrypt(str); + System.out.println(str); + } +} diff --git a/src/main/java/com/itstyle/seckill/common/encrypt/SecurityBase64.java b/src/main/java/com/itstyle/seckill/common/encrypt/SecurityBase64.java new file mode 100644 index 0000000..33289b7 --- /dev/null +++ b/src/main/java/com/itstyle/seckill/common/encrypt/SecurityBase64.java @@ -0,0 +1,49 @@ +package com.itstyle.seckill.common.encrypt; + +import java.io.UnsupportedEncodingException; + +import sun.misc.BASE64Decoder; +import sun.misc.BASE64Encoder; + +/** + * Base64 也会经常用作一个简单的“加密”来保护某些数据,而真正的加密通常都比较繁琐。 + */ +public class SecurityBase64 { + // 加密 + public String getBase64(String str) { + byte[] b = null; + String s = null; + try { + b = str.getBytes("utf-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + if (b != null) { + s = new BASE64Encoder().encode(b); + } + return s; + } + + // 解密 + public String getFromBase64(String s) { + byte[] b = null; + String result = null; + if (s != null) { + BASE64Decoder decoder = new BASE64Decoder(); + try { + b = decoder.decodeBuffer(s); + result = new String(b, "utf-8"); + } catch (Exception e) { + e.printStackTrace(); + } + } + return result; + } + + public static void main(String args[]){ + SecurityBase64 b6 = new SecurityBase64(); + System.out.println(b6.getBase64("ILoveYou"));//加密 + System.out.println(b6.getFromBase64(b6.getBase64("ILoveYou")));//解密 + } + +} diff --git a/src/main/java/com/itstyle/seckill/common/encrypt/SecurityDES.java b/src/main/java/com/itstyle/seckill/common/encrypt/SecurityDES.java new file mode 100644 index 0000000..6c209ae --- /dev/null +++ b/src/main/java/com/itstyle/seckill/common/encrypt/SecurityDES.java @@ -0,0 +1,93 @@ +package com.itstyle.seckill.common.encrypt; + +import java.security.Key; +import java.security.NoSuchAlgorithmException; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.spec.SecretKeySpec; + +/** + * 对称加密 + * 这里面的API里面有很多是调用getInstance方法,这个方法的参数有algorithm或者transformation + * 一:algorithm:算法 + * + * 二:transformation:有两种格式 + * 1:算法/模式/填充方式。如:DES/CBC/PKCS5Padding + * 2:算法。 如:DES + * + * 其中,algorithm、transformation的值,不区分大小写 + * + * Java加密解密官方参考文档: + * https://docs.oracle.com/javase/8/docs/technotes/guides/security/index.html + * https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html + */ +public class SecurityDES { + /* + * 使用KeyGenerator生成key + * + * 其中,algorithm支持的算法有:AES、DES、DESEDE、HMACMD5、HMACSHA1、HMACSHA256、RC2等 + * 全部支持的算法见官方文档 + * https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyGenerator + * + */ + public static Key newKeyByKeyGenerator(String algorithm) throws NoSuchAlgorithmException { + KeyGenerator kg = KeyGenerator.getInstance(algorithm); + Key key = kg.generateKey(); + return key; + } + + /** + * 使用SecretKeySpec生成key + * 一般是从一个文件中读取出key的byte数组,然后根据文件key的算法,构建出key对象 + */ + public static Key newKeyBySecretKeySpec(byte[] key, String algorithm) throws NoSuchAlgorithmException { + return new SecretKeySpec(key, algorithm); + } + + /** + * 加密,对字符串进行加密,返回结果为byte数组 + * 保存的时候,可以把byte数组进行base64编码成字符串,或者把byte数组转换成16进制的字符串 + * + * 其中,transformation支持的全部算法见官方文档: + * https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher + */ + public static byte[] encrypt(String transformation, Key key, String password) throws Exception { + Cipher cipher = Cipher.getInstance(transformation); + //加密模式 + cipher.init(Cipher.ENCRYPT_MODE, key); + return cipher.doFinal(password.getBytes()); + } + + /** + * 解密,返回结果为原始字符串 + * + * 其中,transformation支持的全部算法见官方文档: + * https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher + */ + public static String decrypt(String transformation, Key key, byte[] data) throws Exception { + Cipher cipher = Cipher.getInstance(transformation); + //解密模式 + cipher.init(Cipher.DECRYPT_MODE, key); + byte[] result = cipher.doFinal(data); + String password = new String(result); + return password; + } + + public static void main(String[] args) throws Exception { + String password = "123456"; + + String algorithm = "DES"; + String transformation = algorithm; + + //加密解密使用的都是同一个秘钥key + Key key = newKeyByKeyGenerator(algorithm); + System.out.println(" 秘钥: " + key); + //加密 + byte[] passData = encrypt(transformation, key, password); + //解密 + String pass = decrypt(transformation, key, passData); + + System.out.println("解密后的密码 : " + pass); + } +} diff --git a/src/main/java/com/itstyle/seckill/common/encrypt/SecurityRSA.java b/src/main/java/com/itstyle/seckill/common/encrypt/SecurityRSA.java new file mode 100644 index 0000000..56d27d1 --- /dev/null +++ b/src/main/java/com/itstyle/seckill/common/encrypt/SecurityRSA.java @@ -0,0 +1,121 @@ +package com.itstyle.seckill.common.encrypt; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.security.Key; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; + +/** + * RSA公钥加密 + */ +public class SecurityRSA { + public static void makekeyfile(String pubkeyfile, String privatekeyfile) + throws NoSuchAlgorithmException, FileNotFoundException, IOException { + // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象 + KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); + // 初始化密钥对生成器,密钥大小为1024位 + keyPairGen.initialize(1024); + // 生成一个密钥对,保存在keyPair中 + KeyPair keyPair = keyPairGen.generateKeyPair(); + + // 得到私钥 + RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); + + // 得到公钥 + RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); + + // 生成私钥 + ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream( + privatekeyfile)); + oos.writeObject(privateKey); + oos.flush(); + oos.close(); + + oos = new ObjectOutputStream(new FileOutputStream(pubkeyfile)); + oos.writeObject(publicKey); + oos.flush(); + oos.close(); + + System.out.println("make file ok!"); + } + + /** + * + * @param k + * @param data + * @param encrypt + * 1 加密 0解密 + * @return + * @throws NoSuchPaddingException + * @throws Exception + */ + public static byte[] handleData(Key k, byte[] data, int encrypt) + throws Exception { + + if (k != null) { + + Cipher cipher = Cipher.getInstance("RSA"); + + if (encrypt == 1) { + cipher.init(Cipher.ENCRYPT_MODE, k); + byte[] resultBytes = cipher.doFinal(data); + return resultBytes; + } else if (encrypt == 0) { + cipher.init(Cipher.DECRYPT_MODE, k); + byte[] resultBytes = cipher.doFinal(data); + return resultBytes; + } else { + System.out.println("参数必须为: 1 加密 0解密"); + } + } + return null; + } + + public static void main(String[] args) throws Exception { + //创建目录 + String pubfile = "d:/temp/pub.key"; + String prifile = "d:/temp/pri.key"; + + makekeyfile(pubfile, prifile); + + ObjectInputStream ois = new ObjectInputStream(new FileInputStream(pubfile)); + RSAPublicKey pubkey = (RSAPublicKey) ois.readObject(); + ois.close(); + + ois = new ObjectInputStream(new FileInputStream(prifile)); + RSAPrivateKey prikey = (RSAPrivateKey) ois.readObject(); + ois.close(); + + // 使用公钥加密 + String msg = "爪哇笔记-秒杀项目"; + String enc = "UTF-8"; + + // 使用公钥加密私钥解密 + System.out.println("原文: " + msg); + byte[] result = handleData(pubkey, msg.getBytes(enc), 1); + System.out.println("加密: " + new String(result, enc)); + byte[] deresult = handleData(prikey, result, 0); + System.out.println("解密: " + new String(deresult, enc)); + + msg = "秒杀项目"; + // 使用私钥加密公钥解密 + System.out.println("原文: " + msg); + byte[] result2 = handleData(prikey, msg.getBytes(enc), 1); + System.out.println("加密: " + new String(result2, enc)); + byte[] deresult2 = handleData(pubkey, result2, 0); + System.out.println("解密: " + new String(deresult2, enc)); + + } + +} diff --git a/src/main/java/com/itstyle/seckill/service/impl/SeckillServiceImpl.java b/src/main/java/com/itstyle/seckill/service/impl/SeckillServiceImpl.java index e42150f..1b0502d 100644 --- a/src/main/java/com/itstyle/seckill/service/impl/SeckillServiceImpl.java +++ b/src/main/java/com/itstyle/seckill/service/impl/SeckillServiceImpl.java @@ -204,4 +204,9 @@ public class SeckillServiceImpl implements ISeckillService { } } + @Override + public Result startSeckilTemplate(long seckillId, long userId, long number) { + return null; + } + }