RSA算法的Java实现

RSA大数质因子分解

参考:

https://zhuanlan.zhihu.com/p/35661698 (主要参考,感谢作者)

B站技术蛋的RSA算法科普视频

https://zhuanlan.zhihu.com/p/48249182

以下两篇关于不经意传输:

https://mp.weixin.qq.com/s?__biz=MzIyODYzNTU2OA==&mid=2247490803&idx=1&sn=f21606da1b7856e43d10559ad67653aa

https://cloud.tencent.com/developer/article/1955134

Java代码
package com.hzydbs.rsa;

import java.math.BigInteger;

/**
 * 求最大公约数
 * 
 * @author 北门大官人
 *
 */
public class GCD {
    /**
     * <p>
     * 辗转相除法求最大公约数
     * 
     * @param a
     * @param b
     * @return
     */
    public BigInteger gcd(BigInteger a, BigInteger b) {
        if (b.equals(BigInteger.ZERO)) {
            return a;
        } else {
            return gcd(b, a.mod(b));
        }
    }

    /**
     * <p>
     * 扩展欧几里得算法:
     * <p>
     * 求ax + by = 1中的x与y的整数解(a,b互质)
     * 
     * @param a
     * @param b
     * @return
     */
    public BigInteger[] extGcd(BigInteger a, BigInteger b) {
        if (b.equals(BigInteger.ZERO)) {
            BigInteger x1 = BigInteger.ONE;
            BigInteger y1 = BigInteger.ZERO;
            BigInteger x = x1;
            BigInteger y = y1;
            BigInteger r = a;
            BigInteger[] result = { r, x, y };
            return result;
        } else {
            BigInteger[] temp = extGcd(b, a.mod(b));
            BigInteger r = temp[0];
            BigInteger x1 = temp[1];
            BigInteger y1 = temp[2];

            BigInteger x = y1;
            BigInteger y = x1.subtract(a.divide(b).multiply(y1));
            BigInteger[] result = { r, x, y };
            return result;
        }
    }
}
package com.hzydbs.rsa;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

/**
 * 主要用于计算超大整数超大次幂然后对超大的整数取模。 我在网上查询到这个算法叫做"蒙哥马利算法"。
 * 
 * @author 北门大官人
 */
public class Exponentiation {

    /**
     * 超大整数超大次幂然后对超大的整数取模 (base ^ exponent) mod n
     * 
     * @param base
     * @param exponent
     * @param n
     * @return
     */
    public BigInteger expMode(BigInteger base, BigInteger exponent, BigInteger n) {
        char[] binaryArray = new StringBuilder(exponent.toString(2)).reverse().toString().toCharArray();
        int r = binaryArray.length;
        List<BigInteger> baseArray = new ArrayList<BigInteger>();

        BigInteger preBase = base;
        baseArray.add(preBase);
        for (int i = 0; i < r - 1; i++) {
            BigInteger nextBase = preBase.multiply(preBase).mod(n);
            baseArray.add(nextBase);
            preBase = nextBase;
        }
        BigInteger a_w_b = this.multi(baseArray.toArray(new BigInteger[baseArray.size()]), binaryArray, n);
        return a_w_b.mod(n);
    }

    private BigInteger multi(BigInteger[] array, char[] bin_array, BigInteger n) {
        BigInteger result = BigInteger.ONE;
        for (int index = 0; index < array.length; index++) {
            BigInteger a = array[index];
            if (bin_array[index] == '0') {
                continue;
            }
            result = result.multiply(a);
            result = result.mod(n);
        }
        return result;
    }

}
package com.hzydbs.rsa;

import java.math.BigInteger;
import java.security.SecureRandom;

/**
 * RSA加密、解密、测试正确性
 * 
 * @author 北门大官人
 *
 */
public class RSA {
    /**
     * <pre>
     def gen_key(p, q):
        n = p * q
        fy = (p - 1) * (q - 1)
        e = 3889
        # generate d
        a = e
        b = fy
        r, x, y = ext_gcd(a, b)
        print x
        d = x
        # 公钥    私钥
        return (n, e), (n, d)
     * </pre>
     * 
     * @param p
     * @param q
     * @return
     */
    public BigInteger[][] genKey(BigInteger p, BigInteger q) {
        BigInteger n = p.multiply(q);
        BigInteger fy = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE));
        BigInteger e = new BigInteger("65537");
        // generate d
        BigInteger a = e;
        BigInteger b = fy;
        BigInteger[] rxy = new GCD().extGcd(a, b);
        BigInteger r = rxy[0];
        BigInteger x = rxy[1];
        BigInteger y = rxy[2];

        BigInteger d = x;
        // 对于计算出来的负数d,需要d=d+fy
        if (d.compareTo(BigInteger.valueOf(0)) < 0) {
            d = d.add(fy);
        }
        // 公钥 私钥
        return new BigInteger[][] { { n, e }, { n, d } };
    }

    /**
     * 加密
     * 
     * @param m      被加密的信息转化成为大整数m
     * @param pubkey 公钥
     * @return
     */
    public BigInteger encrypt(BigInteger m, BigInteger[] pubkey) {
        BigInteger n = pubkey[0];
        BigInteger e = pubkey[1];

        BigInteger c = new Exponentiation().expMode(m, e, n);
        return c;
    }

    /**
     * 解密
     * 
     * @param c
     * @param selfkey 私钥
     * @return
     */
    public BigInteger decrypt(BigInteger c, BigInteger[] selfkey) {
        BigInteger n = selfkey[0];
        BigInteger d = selfkey[1];

        BigInteger m = new Exponentiation().expMode(c, d, n);
        return m;
    }

    public static void main(String[] args) {
        // 公钥私钥中用到的两个大质数p,q'''
        /*
        BigInteger p = new BigInteger(
                "106697219132480173106064317148705638676529121742557567770857687729397446898790451577487723991083173010242416863238099716044775658681981821407922722052778958942891831033512463262741053961681512908218003840408526915629689432111480588966800949428079015682624591636010678691927285321708935076221951173426894836169");
        BigInteger q = new BigInteger(
                "144819424465842307806353672547344125290716753535239658417883828941232509622838692761917211806963011168822281666033695157426515864265527046213326145174398018859056439431422867957079149967592078894410082695714160599647180947207504108618794637872261572262805565517756922288320779308895819726074229154002310375209");
        */
        SecureRandom rnd=new SecureRandom();
        
        BigInteger p = BigInteger.probablePrime(2500, rnd);
        BigInteger q = BigInteger.probablePrime(2500, rnd);
        
        System.out.println("p=" + p);
        System.out.println("q=" + q);
        RSA rsa = new RSA();
        // 生成公钥私钥'''
        // pubkey, selfkey = gen_key(p, q)
        BigInteger[][] keys = rsa.genKey(p, q);
        BigInteger[] pubkey = keys[0];
        BigInteger[] selfkey = keys[1];

        // 需要被加密的信息转化成数字,长度小于秘钥n的长度,如果信息长度大于n的长度,那么分段进行加密,分段解密即可。'''
        BigInteger m = new BigInteger(
                "29552253920430244480935420141729228591524107699469182582408239360121179899450577101476579710345554967100561598716023732513996495299410141662749947786005937244656977738527833097623686415626468060988878281679146322528426363279034015388479917760840595285028058423329215856830057760069403267618402231064409756303753621261963998813245801555345709331865159424057596639080245793103551936729636763453083968195850372838520989535777891088951977529791342466901072485266582229616711047022114660121787354697672738075015287123936759958670135509278509350942132843134489493757755637523878155960314647723130468403810490573692371076668554081340711245013791760785972574183759777397663251563223522608282216156466237180692442271370955990451855629775212854995231450914759478136490035502825158538196415358501643051890005641780888343155829469962364157099845810220506084696098509487269528261738091603323397419416656531789855253870506832308483358363624293730162838161876883346182295801408785755959876699692983735536512143262257444692944221679236546240285743514676999000313320454652069198094628016190512249847885741233538694420190674827537926410498871218493798919040337011039226994754553313541467307192132768688698365695235674392298409676883545188918324372058782178620981923190334246098709749931778763297900223981313803899058107970787765589467633684966955996721171175415015860487524541409512786880456374877432683366318130671454224149144855682834737499745953873548378153316742130648196857516669493425502266531024732408366848110881647");
        System.out.println("被加密信息:" + m);
        // 信息加密'''
        BigInteger c = rsa.encrypt(m, pubkey);
        System.out.println("密文:" + c);
        // 信息解密'''
        BigInteger d = rsa.decrypt(c, selfkey);
        System.out.println("被解密后信息:" + d);
        
        
        
        System.out.println("再生成一对公私钥");
        p = BigInteger.probablePrime(2500, rnd);
        q = BigInteger.probablePrime(2500, rnd);
        System.out.println("p=" + p);
        System.out.println("q=" + q);
        keys = rsa.genKey(p, q);
        pubkey = keys[0];
        selfkey = keys[1];
        d = rsa.decrypt(c, selfkey);
        System.out.println("用新私钥解密原来的加密信息,得到:" + d);
    }
}

输出:

p=207705994119526370635869161069954229565107391387932304286553703306274121740633492598868287084647560498962361499214780454785819463801042336298083151123748850658773816003307962941619802856793616120731378783956567022870348363943931882870047928671419853619800298795745829246629031588074575380073256206465894642012481605099372604844186271754793348159995014012945750624659636311109630232644471853209174147632930519002807323175412569886246072456133782441253328997579963555894686075100710472028876913448641629646655981966186844212452879306620361697658069477420761828919042003642944412273603431027195785616212879545811630007744756747682775115144655026132025713591801215667933217220274218162164878761832318548509324500279831774279464196793862379119772913462229607
q=348310505184729662936448255921060459025650190470407992725460408515791175907253795321475916262374052909971540852173723956024631301790912099677965846629870816661742620079406260416636667658419001319297834827736625724299337971361193483143324291127607755987650957491698589642857779249204597314804395301094241235207960037676472023337138228608255312461514687640507920192601273607211421082580682890779460019383429967949863786488245574406881037760527063281356991797695196210502353472562534425229257582836920659020851711042805411637850256413082315206646222557868545204744469779763851403488721666952406009130139948931659582618376856570810347739380323989258222820776273746099806485192655367017231064754230320347764582752041580638419274714391432700000459430743153231
被加密信息:29552253920430244480935420141729228591524107699469182582408239360121179899450577101476579710345554967100561598716023732513996495299410141662749947786005937244656977738527833097623686415626468060988878281679146322528426363279034015388479917760840595285028058423329215856830057760069403267618402231064409756303753621261963998813245801555345709331865159424057596639080245793103551936729636763453083968195850372838520989535777891088951977529791342466901072485266582229616711047022114660121787354697672738075015287123936759958670135509278509350942132843134489493757755637523878155960314647723130468403810490573692371076668554081340711245013791760785972574183759777397663251563223522608282216156466237180692442271370955990451855629775212854995231450914759478136490035502825158538196415358501643051890005641780888343155829469962364157099845810220506084696098509487269528261738091603323397419416656531789855253870506832308483358363624293730162838161876883346182295801408785755959876699692983735536512143262257444692944221679236546240285743514676999000313320454652069198094628016190512249847885741233538694420190674827537926410498871218493798919040337011039226994754553313541467307192132768688698365695235674392298409676883545188918324372058782178620981923190334246098709749931778763297900223981313803899058107970787765589467633684966955996721171175415015860487524541409512786880456374877432683366318130671454224149144855682834737499745953873548378153316742130648196857516669493425502266531024732408366848110881647
密文:7241339024148544379659284979991371008614040507243620421150799770488524128645764738821846700642590467913096659844624897346552373634954027488409631127570771391139969568503650530736258485427456790281650639401901516721690660917184489660537964450096521349299628483467611082805603310135527593980844780084991587142543419073220468057408165268964268246906208877740765178199016084472562393810389367011218677961039289760409655551990731282483651773334903874927777324731832714382395307264594705329122238999523812411288067010532884707144620794694834100725043011131896681551479175772235621357690779733496971945583773137282639193902851817457565106140979379252307430335652879592496910588060545794869208346038202198532122128827479623672130267386311622763396036727358800902891232463840307275407451106639976927242026502998019379413869727566040720820323570408898574156747419782011184696927348855403350895966224792837275679413981580211448662455732275188558169935142012913563951542569430470362911248208429394092682179042370187856557661647676391968644067368663526251858079355225379683452125155280642869731326947638187446212303994162390663738604651513747888786731347178190949503034855566049329567245079937146795905005078336392567728787898355171185066540096530733535894598787334864407163333788766513927212184370297779225862069039330745732479084932093127740666558467306200606016527483322566882042593599315493959827699110776770483511132636336005409246897136115874770623757165635076002713618465968436479197609049706895215140734272059
被解密后信息:29552253920430244480935420141729228591524107699469182582408239360121179899450577101476579710345554967100561598716023732513996495299410141662749947786005937244656977738527833097623686415626468060988878281679146322528426363279034015388479917760840595285028058423329215856830057760069403267618402231064409756303753621261963998813245801555345709331865159424057596639080245793103551936729636763453083968195850372838520989535777891088951977529791342466901072485266582229616711047022114660121787354697672738075015287123936759958670135509278509350942132843134489493757755637523878155960314647723130468403810490573692371076668554081340711245013791760785972574183759777397663251563223522608282216156466237180692442271370955990451855629775212854995231450914759478136490035502825158538196415358501643051890005641780888343155829469962364157099845810220506084696098509487269528261738091603323397419416656531789855253870506832308483358363624293730162838161876883346182295801408785755959876699692983735536512143262257444692944221679236546240285743514676999000313320454652069198094628016190512249847885741233538694420190674827537926410498871218493798919040337011039226994754553313541467307192132768688698365695235674392298409676883545188918324372058782178620981923190334246098709749931778763297900223981313803899058107970787765589467633684966955996721171175415015860487524541409512786880456374877432683366318130671454224149144855682834737499745953873548378153316742130648196857516669493425502266531024732408366848110881647
再生成一对公私钥
p=273592101471818945571881524219361920560443779203827473459751290858352146592152279126682355504289457293693550766332747072095838560206621526758917260061112654933135465300082805884487473196367679211464600301051832755293964770080286404297719253466611284613942292764400476057596463027958592665841846040074179573410070018548532033034908199542401360516920719816841124620928412495002590155696641959444384118539023756818135896496906104614946111929456501917177873888775172283221129218548990243312701311635352661346339727659084429822155432014477474588082618480217728732086016111025091584381155086433657468469978378687329590772381981211789870919801284417534319413689904830835630041283456614452600624838325715796407488451179477894877244456133224738723620231709578951
q=188013569879983117122188708891765309755871325850276616379679080658502805953589292452815703093805334451252146223340042334389608705085724906971274546936095978363301312910048601843746498632428982282511837742009247942543808889090306130955044255960058599895401965526080755167610464140171299370089152319802987592819496228040588699909935657542034463611524311677533947690391052528280791362907512230099295782453080773545437052825088378929112374980564292575483728273390532664786657674601619454268798463241587446029369596747444761596745656556330853689082586759798297575233463700083113511424314537589766408593516585373267809159019845231662854333756468692017089372215150924998684765994155975086438185072359585201862031153379318663739588668247186995359151420449382003
用新私钥解密原来的加密信息,得到:18259918059527759548487951070183520295246233481885520781797768597066352263621649236861652337183261298219474594833820535902293870683655187091416805818732647276590736076879458108766582219480692118863022465693582453155979588178869696079067490915089918621300303241749019230724814474961306923977250359784016274463872302986772233965856207657672478859833497173152229586185433670992262390304530946418618453883829366399606252713092908878231225606824295889056012106669828875777281482586755439960160449074682581010440386361418220700695023325744755086266145954868791645225539436133077799789602002642965075084086030377835091930242650046725770643815008186562586951871422439989485155272573883962758077481846919939615055985374182469283166173716392330703915402868044306898930747075785897585904779112891750893963510532800153759477547559745387157414387438681216395382999856756212887982102413137186951322856277675609906034395944270822301718419317573848938076715731520609087232395321695442221314320911656620741415280669701354905397633822134261507938102495854416080142410067136035495658533559578478736237876168777207847224868852633942463748143195060794689756385143805279516460579460361454794817209780650057978630265718530285803179190209306958904308107835226307927808045356644129506928098043847721343865917246346202003468495494668226687474760031011497468632335698238090683938945924791754700183333549825516451519679013991177563689996157268440721042674532296376207340761749944055477340187730993442761059508781379826732088485234746
结论

基于RSA的不经意传输关键的一个问题解决了:客户端把AES密钥用n个公钥中的一个加密之后,服务端用所有的n个私钥去解密,都会得到大整数,且这n个大整数没有规律,服务端无法判断哪个是客户端真正的AES密钥明文。

服务端用得到的这n个AES密钥(只有一个是真正的、但服务端不知道)分别去对业务数据去做AES加密,然后把n个业务数据密文返回给客户端,客户端用真正的AES密钥去解密选择的业务数据,且只能解密该条业务数据。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容