Theosoft.Blog

Goddess Light My Path!

虽然之前搭建了自己的Cydia源,不过经过这几天在公司同事们的机器上的安装结果来看,总有部分机器在安装了deb格式的安装包后出现无法启动的bug。(这里首先要感谢所有贡献出你们的iphone、ipad和iTouch给我测试的同事们,软件的发布离不开你们的无私奉献!)因此,最终最外发布的程序格式还是ipa安装包。ipa安装包除了兼容性强以外,最大的好处还是可以和itunes同步,这样即使升级以后也可以方便的同步回来。好了,废话少说,还是来看程序吧。

如果你是使用iphone、ipad或者itouch访问本页的,可以直接点击下面的按钮来安装哦(需要已越狱)!

iPhone版:

iPad版:

先来看看iPhone版,话不多说,先上图:

功能上包括实时气象数据、未来多天的预报、灾害气象预警和自动城市判断等功能,涵盖了全国绝大多数的城市和地区。数据采集自中央气象局(www.weather.com.cn)。有不少同学在抱怨这个网站的数据不准,呵呵。目前正在研究google的天气接口,到时候可以无缝切换过去。

再来看看iPad版。功能上基本保持一致,只有UI有些许变化,包括横屏和竖屏。

最后放出下载连接:

12/21更新至iPhone v1.5.4和iPad v1.7.3版

iPhone版ipa下载

iPad版ipa下载

浏览:588

今天整整忙活了一整天,又是deb打包又是cydia建站,网上查了无数教程,不停得在mac os、windows、linux3个系统间来回切换,终于建起了自己的Cydia源:http://www.theosoft.net/cydia 。虽然里面目前只有一个程序,图标还是正方形的(不像ipa装完后是圆角的),没有签名,没有源和程序的图标,甚至介绍里中文都还是乱码,不过这些都不是问题。至少我成功的发布这个源,成功的发布了我的应用,哈哈。一个值得纪念的日子!

浏览:323

RSA是一种比较常用的非对称加密算法,其原理是基于大整数因数分解的计算安全,这里不做介绍。非对称加密的好处在于其密码分为公钥和私钥两部分,你可以随意分发你的公钥,让用户用来加密数据;等上传到服务器端后再用私钥就可以解密里面的数据。所以,这样的体系特别适合用于客户端–尤其使手机客户端的数据加密,而不用担心你的程序被反编译、破解后泄露了你的密码。

正是因为有着这么好的安全特性,早在年初,我还在使用windows mobile手机的时候,就把RSA算法写入了我的那个利用飞信发短信的客户端里。每当要发送短信时,客户端负责使用公钥将短信内容加密,并连同收件人一起传输到接收数据的服务器上。服务器收到信息后直接存储到数据库里。然后由另一台专门负责短信发送的服务器,每隔1分钟查询一次数据库,发现有需要发送的短信后,用私钥将其解密,并通过飞信发送出去。无论是否发送成功,最终都会再发送一条短信,向我报告本次发送的结果。

自从 10月份换了iphone 4后,第一周我就写了一个ios上不加密的同样功能的程序,但是RSA的加密算法却让我纠结了很长时间。因为原来使用windows mobile的时候,RSA的公钥是以原始数据的形式保存在文件里的。但是到了ios上,苹果似乎并不允许直接使用原始的密钥。google了很久,虽然找了一个可能可行的办法,但是因为非常复杂,需要先将密钥导入手机内的密钥库,然后再取出来,试了很多次一直都没成功。后来在网上某位大牛的指点下发现,虽然ios无法直接使用原始的密钥加密数据,但是对证书的支持确非常好,于是花了2天的时间研究了使用证书加密数据的方法,效果非常好,呵呵。下面简单说一下使用证书加密数据的方法。

首先当然是要生成一张证书。微软的.Net framework SDK为我们提供了一个生成X.509数字证书的命令行工具Makecert.exe。

打开.Net的控制台,使用如下命令生成证书:

makecert -sr LocalMachine -ss My -n CN=Theoservice -sky exchange -pe

Makecert命令的详细说明请参看微软Makecert.exe工具的文档:http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/cptools/html/cpgrfcertificatecreationtoolmakecertexe.asp

这样就生成了一张名为Theoservice的证书到你的电脑里。然后,开始->运行->MMC,打开MMC控制台。文件->添加/删除管理单元->添加按钮->选”证书”->添加->选”计算机账户”->关闭->确定,然后你就可以在 “个人->证书” 里看到刚才生成的证书了。证书采用1024位密钥加密。现在,你需要做得就是导出这张证书。如果你的服务器并不是本机,你首先需要导出一个带私钥的pfx格式的证书。导出时需要你填写密码来保护这张证书,然后将其导入到服务器上就好了。此外,你还需要导出一份不带私钥的cer格式的证书。这张证书只含有公钥,是用来和客户端一起发布出去用来加密数数据的。

证书已经有了,接下来就要写算法来加密和解秘数据了。先来看看C#服务器端的解密过程:

public class RSAHandler
{
const string CERT = “Theoservice”;
const int KEYLENGTH = 128;
const int BLOCKSIZE = KEYLENGTH - 11;

private static X509Certificate2 GetRSACertificate()
{
X509Certificate2 clientCert = null;
if (clientCert == null)
{
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
foreach (var certificate in store.Certificates)
{
if (certificate.GetNameInfo(X509NameType.SimpleName, false== CERT)
{
clientCert = certificate;
break;
}
}
}

return clientCert;
}

public static RSACryptoServiceProvider GetPrivateKey()
{
var clientCert = GetRSACertificate();
var publicKey = (RSACryptoServiceProvider)clientCert.PrivateKey;

return publicKey;
}

public static string RSADecrypt(string rawText, RSACryptoServiceProvider rsa)
{
try
{
var encryptedBytes = Convert.FromBase64String(rawText);
int numBlock = encryptedBytes.Length / KEYLENGTH;
byte[] rawResult = new byte[0];
var buffer = new byte[KEYLENGTH];
for (var= 0; i < numBlock; i++)
{
Array.Copy(encryptedBytes, i * KEYLENGTH, buffer, 0, buffer.Length);
var decryptedBytes = rsa.Decrypt(buffer, false);
var resultBuffer = new byte[rawResult.Length + decryptedBytes.Length];
Array.Copy(rawResult, resultBuffer, rawResult.Length);
Array.Copy(decryptedBytes, 0, resultBuffer, rawResult.Length, decryptedBytes.Length);
rawResult = resultBuffer;
}

var plaintext = Encoding.UTF8.GetString(rawResult);
return plaintext;
}
catch (CryptographicException e)
{
return e.Message;
}
}
}

这个类里面有两个public的函数:GetPrivateKey()和RSADecrypt()。前者用来从电脑的密钥库中找到指定的证书,并取出该证书的私钥;后者则使用密钥将数据解密。为了方便在存储和传输,所有加密后的数据都采用base64编码,所以RSADecrypt在解密数据之前首先做base64解码,然后计算密文的长度,分组解密。这里需要普及一下RSA分组加密的知识:因为采用了1024位的密钥,所以密钥长度为1024/8=128个byte。而C#默认采用#PKSC1的padding模式,每次最多可以加密128-11=117个byte。也就是说,RSA分组加密算法每次从明文里取<=117个byte,然后加密成128个byte的密文;解密的时候,每次就取128个byte的密文,将其解密成<=117个byte的明文。因为#PKSC1的padding模式每次padding的内容是随机的,所以即使是加密同一段明文,每次的结果也不一样,这大大的增加了数据安全性。最后把所有解密的结果连起来,识别成utf-8格式的字符串,就是我们之前加密的明文了。

再来看看手机客户端的加密算法:

- (SecKeyRef)getPublicKey{

NSString *certPath = [[NSBundle mainBundle] pathForResource:@”Theoservice” ofType:@”cer”];

SecCertificateRef myCertificate = nil;

NSData *certificateData = [[NSData alloc] initWithContentsOfFile:certPath];

myCertificate = SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef)certificateData);

SecPolicyRef myPolicy = SecPolicyCreateBasicX509();

SecTrustRef myTrust;

OSStatus status = SecTrustCreateWithCertificates(myCertificate,myPolicy,&myTrust);

SecTrustResultType trustResult;

if (status == noErr) {

status = SecTrustEvaluate(myTrust, &trustResult);

}

return SecTrustCopyPublicKey(myTrust);

}

- (NSData *)encrypt:(NSString *)plainText usingKey:(SecKeyRef)key error:(NSError **)err

{

size_t cipherBufferSize = SecKeyGetBlockSize(key);

uint8_t *cipherBuffer = NULL;

cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t));

memset((void *)cipherBuffer, 0×0, cipherBufferSize);

NSData *plainTextBytes = [plainText dataUsingEncoding:NSUTF8StringEncoding];

int blockSize = cipherBufferSize – 11;

int numBlock = (int)ceil([plainTextBytes length] / (double)blockSize);

NSMutableData *encryptedData = [[NSMutableData alloc] init];

for (int i=0; i<numBlock; i++) {

int bufferSize = MIN(blockSize,[plainTextBytes length] – i * blockSize);

NSData *buffer = [plainTextBytes subdataWithRange:NSMakeRange(i * blockSize, bufferSize)];

OSStatus status = SecKeyEncrypt(key, kSecPaddingPKCS1,

(const uint8_t *)[buffer bytes],

[buffer length], cipherBuffer,

&cipherBufferSize);

if (status == noErr)

{

NSData *encryptedBytes = [[[NSData alloc]

initWithBytes:(const void *)cipherBuffer

length:cipherBufferSize] autorelease];

[encryptedData appendData:encryptedBytes];

}

else

{

*err = [NSError errorWithDomain:@"errorDomain" code:status userInfo:nil];

NSLog(@”encrypt:usingKey: Error: %d”, status);

return nil;

}

}

if (cipherBuffer)

{

free(cipherBuffer);

}

NSLog(@”Encrypted text (%d bytes): %@”,

[encryptedData length], [encryptedData description]);

return encryptedData;

}

加密算法和解密差不多,就是每次取117个byte的明文并加密成128个byte的密文,最后连起来做base64编码。需要注意的是公钥的获取方法getPublicKey。前面不是导出了一张只含有公钥的cer格式的证书吗?现在把它加到程序的Resources里,这里取名Theoservice.cer。然后通过[[NSBundle mainBundle] pathForResource:@”Theoservice” ofType:@”cer”]就可以把里面的内容读出来,生成SecCertificateRef实体。然后用分别创建一个SecPolicyRef和SecTrustRef,就可以获取到这个公钥的SecKeyRef了,其实还是蛮简单的,不是吗?!

最后,来show一下最新的iphone版短信发送程序,哈哈!

浏览:482

我们家其实没有装宽带,网线是从楼上的一户人家家里拉过来的。他们家是2M的ADSL宽带,平时用的也不多;又因为是包月的,商量好每家轮流付账单,在他们家装了个路由器,很顺利的就把网线接到了家里。当然,为了在家里用的方便,网线接回来后我又接了一个无线路由器,方便笔记本和手机使用。

当年是因为觉得放在人家家里的,不用买很好的那种路由器,就买了个最便宜的R402m。后来才发现,这个路由器没有DDNS(动态域名解析),也没有qos。没有DDNS也就算了,但是没有qos对于这个共享的宽带来说,有时实在是让人无法忍受。人家只要一下bt或者在看视频,我这里基本上就什么事都干不了了。尤其是那段在国服wow的日子,总是把延迟搞到1k以上,走在野外莫名其妙的就死了。后来也在网上搜了很久,一直都没有找到带qos的rom可以刷。

今天不知道是怎么了,突然心血来潮,在Google上搜了“r402m qos”这个关键词。没想到居然还真的找到一个今年1月份出的测试版rom,真的就带qos功能,所以立马就下下来刷了。看上去感觉还不错,不过到底有多少用,就不得而知了。rom我也一起发出来,需要的tx可以刷一下试试。(立即下载

, 浏览:2,691

今天终于把Theosoft.Blog搬进了DreamHost的空间。虽然原先GoDaddy的免费空间用着也蛮好,但是毕竟是免费的,限制比较多,而且经常会有广告,很烦人。网上虽然也有去掉广告的方法,但是毕竟不太好。再加上免费空间的数据库不允许远程连接,国内的两个空间虽然还没到期,但是一个3天2头当机,另一个已经因为同IP的某个站点没备案,被封了。(这里要好好庆祝一下,还好自己事先把网站搬到国外去了,不要然又是一场灭顶之灾-_-!)。用飞信每天给大家发送天气预报的服务,为了提高系统稳定性,现在已经被我写成了windows service,连接远程的数据库来获取配置信息和写入日志。所以,为了这个可以远程连接的数据库,也必须要出钱买一个空间。再加上GoDaddy的空间本来就觉得有点慢,换成DreamHost就要好很多。

由于DreamHost是Linux的主机,所以以前用.Net写的Webservice的服务没办法一起搬过来,就被留在了GoDaddy,并且启用新的2级域名http://api.theosoft.net/来访问。放在GoDaddy的免费空间上,所以难免会有广告。如果因为广告的问题,使得在Visual Studio里引用有问题的话,可以直接引用WSDL的地址http://api.theosoft.net/theoservice.asmx?WSDL

有了一个稳定的空间和数据库,接下来就要开始完善用飞信实现的“天气预报短信系统”。可能打算做一套会员管理系统,支持用户登录后的管理自己定制的天气预报短信的地点和时间。目前这套系统已经可以支持全国3百多个主要城市和地区,也支持为双修日定制一个特别的发送时间(喜欢睡懒觉的就不用担心再被短信吵醒啦)。但是因为一直没有一个稳定的空间和数据库,一直没有开发出管理界面,所以这套系统也长时间得处于内测阶段。如果你迫不及待的想要尝试一下免费的天气预报短信服务,灰常欢迎来当我的小白鼠哦!

, , , , , , 浏览:789