dal*_*tec 8 encryption coldfusion cryptography single-sign-on private-key
我提前为这篇文章的篇幅道歉.我真的不太了解这个问题,无法正确识别具体问题实际上是什么!但无论如何,我们已经做出有悖于我们的会员API调用,查询有关我们的会员信息(加入日期,会员类型等)使用@Leigh提供的步骤和建议,在这里,他们一直在努力太棒了!再次感谢Leigh,我们的会员非常高兴能够做到这一点!
现在我想为我们的会员设置单点登录,允许他们在我们的页面登录,然后被提交到他们已经登录该网站的会员资料.根据API文档,我需要做的一件事是:
"使用签名证书签署登录人员的Portal用户名."
我完全坚持这个.我在表单中获得了一个XML私钥(由他们的.NET应用程序生成)
<RSAKeyValue><Modulus>{stuff}</Modulus><Exponent>{stuff}</Exponent><P>... etc etc
Run Code Online (Sandbox Code Playgroud)
我认为我无法直接使用此格式,必须将其转换为PEM格式或类似格式.使用OpenSSL,我想我已经完成了这个,现在有一个格式为"----- BEGIN PRIVATE KEY ----- {stuff} ----- END PRIVATE KEY -----"的文件.
使用Leigh的解决方案确实给了我一个签名,但它与API文档中提供的示例不匹配.我认为这是因为它使用HmacSHA1,而他们注意到"标题中的签名使用HMAC SHA1而创建安全令牌的签名使用公钥/私钥对和RSA-SHA1.同样的方法不能用于生成两者. " 我试过改变
<cfset key = key.init(jKey,"HmacSHA1") />
Run Code Online (Sandbox Code Playgroud)
至
<cfset key = key.init(jKey,"RSA-SHA1") />
Run Code Online (Sandbox Code Playgroud)
得到"算法RSA-SHA1不可用".
我曾尝试复制和粘贴其他一些建议的解决方案,但它们都不起作用.一个例子(来自12Robots.com):
<!--- Create a Java Cipher object and get a mode --->
<cfset cipher = createObject('java', 'javax.crypto.Cipher').getInstance("RSA") />
<!--- The mode tells the Cipher whether is will be encrypting or decrypting --->
<cfset encMode = cipher.ENCRYPT_MODE />
<cfset encryptedValue = "" /> <!--- Return variable --->
<!--- Initialize the Cipher with the mode and the key --->
<cfset cipher.init(encMode, key) />
<!--- Convert the string to bytes --->
<cfset stringBytes = stringToSign.getBytes("UTF8") />
<!--- Perform encryption --->
<cfset encryptedValue = cipher.doFinal(stringBytes, 0, len(inputString)) />
<cfdump var="#encryptedValue#">
Run Code Online (Sandbox Code Playgroud)
这个例子中的"密钥"是我之前提到的PEM文本,"stringToSign"是用户名.我得到的错误是"要么没有指定方法名称和参数类型的方法,要么init方法重载了ColdFusion无法可靠解密的参数类型.ColdFusion找到了0个与提供的参数匹配的方法.如果这是一个Java对象并且您验证了该方法存在,使用javacast函数来减少歧义."
我尝试的另一件事是:
<cfset rsaPrivateKey = toBase64(key, "utf-8")>
<cfset jKey = JavaCast("string", rsaPrivateKey)>
<cfset jMsg = JavaCast("string", stringToSign).getBytes("ASCII")>
<cfset key = createObject("java", "java.security.PrivateKey")>
<cfset keySpec = createObject("java", "java.security.spec.PKCS8EncodedKeySpec")>
<cfset keyFactory = createObject("java", "java.security.KeyFactory")>
<cfset b64dec = createObject("java", "sun.misc.BASE64Decoder")>
<cfset sig = createObject("java", "java.security.Signature")>
<cfset byteClass = createObject("java", "java.lang.Class")>
<cfset byteArray = createObject("java", "java.lang.reflect.Array")>
<cfset byteClass = byteClass.forName(JavaCast("string", "java.lang.Byte"))>
<cfset keyBytes = byteArray.newInstance(byteClass, JavaCast("int", "1024"))>
<cfset keyBytes = b64dec.decodeBuffer(jKey)>
<cfset sig = sig.getInstance("SHA1withRSA", "SunJSSE")>
<cfset sig.initSign(keyFactory.getInstance("RSA").generatePrivate(keySpec.init(keyBytes)))>
<cfset sig.update(jMsg)>
<cfset signBytes = sig.sign()>
<cfset finalSig = ToBase64(signBytes)>
<cfdump var="#finalSig#">
Run Code Online (Sandbox Code Playgroud)
这给了我"java.security.InvalidKeyException:无效的密钥格式." 顺便说一句,如果我将rsaPrivateKey设置为"key",我会得到一个不同的错误,"java.security.InvalidKeyException:IOException:DerInputStream.getLength():lengthTag = 127,太大了." 我很高兴得到不同的错误信息; 至少有些事情正在发生!:-)
同样,我不知道这些Java函数在做什么.我肯定不明白为什么看似简单的事情变得如此复杂!但我的怀疑是,我已经错误地存储了私钥PEM,或者正在错误地(或两者)读出数据库,这就是导致这些各种解决方案失败的原因.但我不知道是否确实如此.
我欢迎任何有助于我的见解或建议!如果有人需要更多信息,我很乐意提供.非常感谢大家!
我发现无法直接使用此格式,因此必须将其转换为PEM格式或类似格式
这样做没什么问题,但这在技术上不是必需的。密钥信息既可以从PEM文件中加载,也可以直接从XML中加载。
选项1:从XML加载密钥:
将样本XML字符串解析为一个对象。然后提取模数和私有指数(即<D>元素)。使用模数和指数来创建RSAPrivateKeySpec并加载RSA私钥:
xmlKeyString = "<RSAKeyValue><Modulus>........</D></RSAKeyValue>";
xmlDoc = xmlParse(xmlKeyString);
modBytes = binaryDecode(xmlDoc.RSAKeyValue.Modulus.xmlText, "base64");
dBytes = binaryDecode(xmlDoc.RSAKeyValue.D.xmlText, "base64");
modulus = createObject("java","java.math.BigInteger").init(1, modBytes);
exponent = createObject("java","java.math.BigInteger").init(1, dBytes);
keySpec = createObject("java", "java.security.spec.RSAPrivateKeySpec").init(modulus, exponent);
keyFactory = createObject("java", "java.security.KeyFactory").getInstance("RSA");
privateKey = keyFactory.generatePrivate(keySpec);
Run Code Online (Sandbox Code Playgroud)
选项2:从PEM文件加载密钥:
将PEM文件读入变量。删除标题/尾部,即“ --- BEGIN / END RSA PRIVATE KEY -----”。然后解码base64内容并使用KeyFactory加载私钥:
rawKey = replace( pemContent, "-----BEGIN RSA PRIVATE KEY-----", "" );
rawKey = replace( rawKey, "-----END RSA PRIVATE KEY-----", "" );
keyBytes = rawKey.trim().binaryDecode("base64");
keySpec = createObject("java", "java.security.spec.PKCS8EncodedKeySpec");
keyFactory = createObject("java", "java.security.KeyFactory").getInstance("RSA");
privateKey = keyFactory.generatePrivate(keySpec.init(keyBytes));
Run Code Online (Sandbox Code Playgroud)
加载私钥后,可以使用Signature对象执行SHA1哈希并使用RSA密钥生成签名:
stringToSign = "test@membersuite.com";
signer = createObject("java", "java.security.Signature").getInstance("SHA1withRSA");;
signer.initSign(privateKey);
signer.update( stringToSign.getBytes("us-ASCII"));
signedBytes = binaryEncode(signer.sign(), "base64");
writeDump(signedBytes);
Run Code Online (Sandbox Code Playgroud)
结果(使用示例XML):
jTDKoH+INi19kGWn7WRk/PZegLv/9fPUOluaM57x8y1tkuwxOiyX86gxsZ7gU/OsStIT9Q5SVSG5NoaL3B+AxjuLY8b7XBMfTXHv2vidrDkkTTBW0D2LsrkZ3xzmvvPqqfA3tF2HXUYF+zoiTsr3bQdA32CJ+lDNkf+QjV3ZEoc=
Run Code Online (Sandbox Code Playgroud)
注意:无论选择哪种方法,正确保护私钥都是非常重要的。一旦您使用了示例,一定要仔细阅读如何最好地存储和保护私钥。
| 归档时间: |
|
| 查看次数: |
655 次 |
| 最近记录: |