1 - Not for resale
2 - Desktop
4 - Web
8 - Database Servers
16 - iOS
32 - Console
64 - Pro
128 - Lite Mac
256 - Lite Windows
512 - Lite Linux
1024 - Pro Plus
2048 - Single Board Computer
other - Unknown
每一个 bit 代表一个版本。
保存 feature 到 keyData 对象:
另外,在保存 feature 时,会检查是否包括 console 和 pro 版本,如果包括这两个版本之一,则加上 Single board computer 版本特性,如下图所示。
这样,StudioKeyData 的 constructor 就执行完了,我们按 "CTRL + F9" 退出函数,来到下面:
BlowFishDecrypt(publicKey As String, data As MemoryBlock, blockMode As Crypto = BlockModes.CBC, initializationVector As MemoryBlock) As MemoryBlock
BlowFishEncrypt(publicKey As String, data As MemoryBlock, blockMode As Crypto = BlockModes.CBC, initializationVector As MemoryBlock) As MemoryBlock
也不是通过这个类来实现的,这两个函数也不能处理超过长度的密码。
以下是注册机的主要代码:
[Visual Basic] 纯文本查看复制代码
const NID_SHA1 as Integer = 64 ////&H40
var features() as int64 = Array(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 2147479552)
var crlf as String = EndOfLine.UNIX
const xml_cryptoKey as String = "+%%o<Graphics>o<RectControl>o<RBControl>i4i4"
//// email and password
var email as String = txtEmail.Text.Trim.Lowercase
if email = "" then
MessageBox "Please Input a Email Address!!!"
exit sub
end if
//if lstEditions.SelectedRowIndex = ListBox.NoSelection then
//MessageBox "Please select edition features!!!"
//exit sub
//end if
///// ==================================================================================================================
///// 生成序列号
var password as string = email
//if password = "" then
//MessageBox "Password(email address) is Null, Input eMail Address First!!!!!!"
//exit sub
//end if
var mem as MemoryBlock = new MemoryBlock(24)
mem.LittleEndian = false
// unused
mem.Int8Value(0) = &H20
// release date
// 2022-04-06
/// shipped_date
var today as date = new Date
var shippedDate as date = dtpShippedDate.SelectedDate
var year as UInt16 = shippedDate.Year
var wks as UInt8 = shippedDate.WeekOfYear
var wDays as UInt8 = shippedDate.DayOfWeek
/// shipped date
mem.UInt16Value(1) = Year
mem.UInt8Value(3) = wks // yestoday
mem.UInt8Value(4) = wDays
/// expiration = valid_days - today - 1
var expiredDays as Integer = CType((dtpLicensedDate.SelectedDate.SecondsFrom1970 - dtpShippedDate.SelectedDate.SecondsFrom1970) / 86400, Integer)
if expiredDays < 0 then
MessageBox "Licensed Date Must be more than Shipped Date!!!"
Exit sub
end if
if expiredDays > (&H7FFE - today.Day) then
MessageBox "Licensed Date too bigger!!!"
Exit sub
end if
//mem.Int16Value(5) = expiredDays //// key的有效天数,默认 365 天,生成的授权文件在 365 天内加入都 有效,否则会失效
mem.Int16Value(5) = &H7FFF - 365
// loop one, [7]>1 则 raise UnsupportedFormatException
mem.Int8Value(7) = 1 // not loop
// unused
mem.Int8Value(8) = &H20
mem.Int8Value(9) = &H20
// SubscriptionID
mem.Int32Value(10) = Integer.FromString(txtSubscriptionID.Text.Trim)//&H88888888
// serial_index
mem.Int16Value(14) = Integer.FromString(txtSerialIndex.Text.Trim) //&H6667
// unused
mem.Int8Value(16) = &H20
//feature
var feature as UInt32 = 0
for i as Integer = 0 to lstEditions.LastRowIndex
if lstEditions.RowAt(i).Selected then
feature = feature or features(i)
end if
next i
if bitwise.BitAnd(feature, &H36) = 0 then //// Desktop, Web, iOS, Console 必选
feature = &H476 // Desktop, Web, iOS, Console, Pro, Pro Plus
end if
mem.UInt32Value(17) = feature//&H7FFFFFFE
// tag
mem.Int8Value(21) = &H2C /// 逗号 ',',序列号有效性标志
// unused
mem.Int8Value(22) = &H20
mem.Int8Value(23) = &H20
//Crypto.BlowFishEncrypt(key As String, data As MemoryBlock, blockMode As BlockModes = BlockModes.CBC, initializationVector As MemoryBlock) As MemoryBlock
var mem2 as MemoryBlock = Crypto.BlowFishEncrypt(password, mem, Crypto.BlockModes.ECB, nil)
var serial_hex as string = mem2.StringValue(0, mem2.Size)
var serial_str as string = EncodeHex(serial_hex)
var serial_xml as string = serial_str.Middle(0, 8) + "-" + serial_str.Middle(8, 8) + "-" + serial_str.Middle(16, 8) + "-" + serial_str.Middle(24, 8) + "-" + serial_str.Middle(32, 8) + "-" + serial_str.Middle(40, 8)
////// debug
////MessageBox "SerialNo: " + serial_xml
////// ==================================================================================================================
///// 生成序列号和地址信息的签名
var privateKey as String = Self.rsa_private_key.ReplaceLineEndings(EndOfLine.UNIX) //// 取得私钥
if privateKey = "" then
MessageBox "RSA private key is null!!!!"
exit sub
end if
//// 用户名,一般为电脑登陆名
var userName as String = txtName.Text.Trim
if userName = "" then
userName = app.LoggedInUserName ///
end if
/// 生成地址信息
var address as String = txtName.Text + crlf + txtAddress1.Text + crlf + txtAddress2.Text + crlf + txtCity.Text + "," + txtProvince.Text + "," + txtPostCode.Text + crlf + txtCountry.Text
address = address.ReplaceLineEndings(EndOfLine.UNIX)
//// 生成RSA签名文本
var msg as String = serial_xml + crlf + address
var signRet as String = ""
var private_key_pem as String = "-----BEGIN PRIVATE KEY-----" + EndOfLine.UNIX + privateKey + EndOfLine.UNIX + "-----END PRIVATE KEY-----"
//var public_key_pem as String = "-----BEGIN PUBLIC KEY-----" + EndOfLine.UNIX + publicKey + EndOfLine.UNIX + "-----END LUBLIC KEY-----"
//// 注意:需要安装插件 OpenSSLPlugin.xojo_plugin,否则不能调用下面4个OpenSSL函数,该插件可自制
//// 注意:需要安装插件 OpenSSLPlugin.xojo_plugin,否则不能调用下面4个OpenSSL函数,该插件可自制
//// 注意:需要安装插件 OpenSSLPlugin.xojo_plugin,否则不能调用下面4个OpenSSL函数,该插件可自制
var rsa as Ptr = OpenSSL.RSA_New()
rsa = OpenSSL.PEM_read_RSAPrivateKey(private_key_pem, rsa)
var isRsaSignOK as Boolean = OpenSSL.RSA_Sign(NID_SHA1, msg, signRet, rsa) //// 生成RSA签名: signRet
OpenSSL.RSA_Free(rsa)
var signRet_str as String = ""
if isRsaSignOK then
signRet_str = EncodeHex(signRet)
//// debugInfo
////MessageBox "RSA Sinature return: " + crlf + signRet_str
else
MessageBox "Generate RSA Signature failure!!!!!!"
exit sub
end if
if signRet_str.Length <> 512 then
MessageBox "Encode RSA Signature failure!!!!!!"
exit sub
end if
////// debug
///taLicenseKeyContent.Text = signRet_str
/////==================================================================================================================
///// 生成 XML 文件的 signature 标签内容
var sign_pass As MemoryBlock = new MemoryBlock(64)
sign_pass.LittleEndian = False
//MD5
var md5Value As MemoryBlock = Crypto.MD5(password)
sign_pass.StringValue(0, 16) = md5Value.StringValue(0,16)
//Serial
sign_pass.StringValue(16, 24) = serial_hex
var signature_password_constant as String = password_retrieval_table //// 含一定的字符串:“CAF", "BAD", "11", "8", "B", "3", "7", "D", "F", "C"等
var signature_verify as String = signRet_str
if signature_verify = "" then
MessageBox "RSA Signature First!!!!!"
exit sub
end if
var pass_str as String
if chkRandomPwdBase.Value then
//var randBytes as MemoryBlock = Crypto.GenerateRandomBytes(256)
//var signature_password_random as String = EncodeHex(randBytes.StringValue(0, 256), false)
var signature_password_random as String = getRandomString() //// 生成随机的密码检索表
//// debugInfo
//// MessageBox "random string: " + signature_password_random
pass_str = signature_password_random //// 随机
else
pass_str = signature_password_constant //// 固定
end if
var sign_verify_str as String = signature_verify
var sign_verify_str_hex as String = app.MyDecodeHex(sign_verify_str) // 16 进制的签名
if pass_str.Length <> 512 then
MessageBox "pass base string length is not 512 bytes!"
exit sub
end if
if sign_verify_str.Length <> 512 then
MessageBox "signature verity string length is not 512 bytes!"
exit sub
end
//MessageBox "sign_verify_str.length = " + sign_verify_str.Length.ToString
//MessageBox "sign_verify_str_hex.length = " + sign_verify_str_hex.Length.ToString
while (sign_verify_str_hex.length mod 8) <> 0
sign_verify_str_hex = sign_verify_str_hex + " "
wend
var count as Integer = 0
var min_val as Integer = 0
var sum_val as Integer = 0
var position as Integer = 0
var start as Integer = 0
var pow_val as Double = 0.0
var str_tmp1 as string = ""
var str_tmp2 as string = ""
var str_tmp3 as string = ""
/// byte(40)
count = CountOfStr(pass_str, "A")
sign_pass.Int8Value(40) = count
/// byte(41)
str_tmp1 = pass_str.Right(1)
str_tmp2 = MidStr(pass_str, pass_str.Length-2, 1)
position = charAt(pass_str, str_tmp2) // Instr()
count = CountOfStr(pass_str, str_tmp1, position)
sign_pass.Int8Value(41) = count
//messagebox str_tmp1 + ", " + str_tmp2 + "," + position.ToString
/// byte(42)
count = CountOfStr(pass_str, "CAF")
sign_pass.Int8Value(42) = count
//messagebox "count of ""CAF"": " + count.ToString
/// byte(43)
count = CountOfStr(pass_str, "8")
sign_pass.Int8Value(43) = count
//messagebox "count of ""8"": " + count.ToString
/// byte(44)
position = charAt(pass_str, "B") // Instr()
min_val = Min(position * 8, 255)
sign_pass.Int8Value(44) = min_val
//messagebox "min of InStr(""B"")*3 between ""255"": " + min_val.ToString
/// byte(45)
count = CountOfStr(pass_str, "BAD")
sign_pass.Int8Value(45) = count
//messagebox "count of ""BAD"": " + count.ToString
//// byte(46)
position = charAt(pass_str, "3") // Instr()
count = CountOfStr(pass_str, "7", position)
min_val = Min(count, 12)
sign_pass.Int8Value(46) = min_val
//messagebox "min of InStr(""7"", InStr(""3"")) between ""12"": " + min_val.ToString
/// byte(47)
sign_pass.Int8Value(47) = 9 /// '\t'
/// byte(48)
sign_pass.Int8Value(48) = password.Length // 用户密码长度
/// byte(49)
str_tmp1 = MidStr(pass_str, 21, 1)
str_tmp2 = MidStr(pass_str, 203, 1)
str_tmp3 = MidStr(pass_str, 48, 1)
sum_val = str_tmp1.Asc + str_tmp2.Asc + str_tmp3.Asc
sign_pass.Int8Value(49) = sum_val
//MessageBox str_tmp1 + ", " + str_tmp2 + ", " + str_tmp3
/// byte(50)
position = charAt(pass_str, "11") // Instr()
if position > 0 then
sign_pass.Int8Value(50) = 1
else
sign_pass.Int8Value(50) = 0 /// 默认就是0,可跳过
end if
/// byte(51)
sign_pass.Int8Value(51) = 42
/// byte(52)
sign_pass.Int8Value(52) = sign_pass.Int8Value(0) /// byte(52) = MD5Bytes[0]
/// byte(53)
sign_pass.Int8Value(53) = sign_pass.Int8Value(31) * 7 /// byte(53) = serialBytes[15] * 7
/// byte(54)
count = CountOfStr(pass_str, "D", 127)
sign_pass.Int8Value(54) = count
/// byte(55)
str_tmp1 = MidStr(pass_str, pass_str.Length-2, 1)
str_tmp2 = pass_str.Right(1)
position = charAt(pass_str, str_tmp2)
count = CountOfStr(pass_str, str_tmp1, position)
sign_pass.Int8Value(55) = count
//MessageBox str_tmp1 + ", " + str_tmp2 + ", pos = " + position.ToString + ", count = " + count.ToString
/// byte(56) ~ byte(63)
position = charAt(pass_str, "F")
count = CountOfStr(pass_str, "C", 1)
pow_val = Pow(position, count)
sign_pass.DoubleValue(56) = pow_val
var sign_pass_string as String = sign_pass.StringValue(0, 64)
/// enrypted signature_verify_part
var sign_verify_data as MemoryBlock = new MemoryBlock(sign_verify_str_hex.Length)
sign_verify_data.StringValue(0, sign_verify_str_hex.Length) = sign_verify_str_hex
//// 加密
var bf as _Blowfish = new _Blowfish(sign_pass_string)
//MessageBox "sign_verify_str_hex.length = " + sign_verify_str_hex.Length.ToString
var data0 as MemoryBlock = new MemoryBlock(sign_verify_str_hex.Length)
data0.StringValue(0, sign_verify_str_hex.Length) = sign_verify_str_hex
var data as MemoryBlock = new MemoryBlock(sign_verify_str_hex.Length)
data.StringValue(0, sign_verify_str_hex.Length) = sign_verify_str_hex
data.LittleEndian = False
bf.Encipher(data) /// 加密
//// 256
var xml_signature as String = ""
var encrypted_signature as String
if data <> nil then
//MessageBox encrypt_verify_data.Size.ToString
encrypted_signature = EncodeHex(data.StringValue(0, data.Size), false)
xml_signature = pass_str + encrypted_signature
//MessageBox "encryped signature: "+ crlf + encrypted_signature
//MessageBox "signature ok!!!"
else
MessageBox "XML Signature is null"
exit sub
end if
////// debug
////taLicenseKeyContent.Text = xml_signature
/////==================================================================================================================
///// 生成 XML 文件内容
if encrypted_signature = "" then
MessageBox "XML Signature is empty."
exit sub
end if
if encrypted_signature.Length <> 512 then
MessageBox "Ecrypted Signature String Length not equal 512"
exit sub
end if
//if pass_str.Length <> 512 then
//MessageBox "Password Base String Length not equal 512"
//exit sub
//end if
//// XML 文件
var xml_str as String = "<?xml version=""1.0"" encoding=""UTF-8""?>" + EndOfLine.Unix + "<key>" + EndOfLine.Unix + "</key>"
var xml as XmlDocument = new XmlDocument()
xml.PreserveWhitespace = true
xml.LoadXml(xml_str)
var xml_element as XmlElement = xml.DocumentElement
var n as Integer = xml_element.ChildCount
var serialNode as XmlTextNode = xml.CreateTextNode(serial_xml)
xml_element.AppendChild(xml.CreateElement("serial")).AppendChild(serialNode)
var addressNode as XmlTextNode = xml.CreateTextNode(address)
xml_element.AppendChild(xml.CreateElement("address")).AppendChild(addressNode)
var emailNode as XmlTextNode = xml.CreateTextNode(email) //// password
xml_element.AppendChild(xml.CreateElement("email")).AppendChild(emailNode)
var signatureNode as XmlTextNode = xml.CreateTextNode(xml_signature)
xml_element.AppendChild(xml.CreateElement("signature")).AppendChild(signatureNode)
////// debug
///taLicenseKeyContent.Text = xml.ToString
/////==================================================================================================================
///// 生成 最终加密的 XML 文件内容
// 加密
var sData as String = xml.ToString.ReplaceLineEndings(EndOfLine.Unix)
while ((sData.Length mod 8) <> 0)
sData = sData + " "
wend
var mbData as MemoryBlock = new MemoryBlock(sData.Length)
mbData.LittleEndian = False
mbData.StringValue(0, sData.Length) = sData
// BlowFishEncrypt(publicKey As String, data As MemoryBlock, blockMode As Crypto = Crypto, initializationVector As MemoryBlock) As MemoryBlock
var encryptData as MemoryBlock = Crypto.BlowFishEncrypt(xml_cryptoKey, mbData, Crypto.blockModes.ECB, Nil)
var encryptedXML as string = EncodeHex(encryptData.StringValue(0, encryptData.Size-8), False) ///// 需要去除 XML 加密后多出来的8个padding字符,否则XMLDocument会出错
////// show license key
taLicenseKeyContent.Text = encryptedXML
////
MessageBox "Generate License Key Success!!!!!"